こんな感じで正規表現の結果を参照したかったので作ってみました
let target = "^/users/(?<user_id>[0-9]+)/items/(?<item_id>[0-9]+)$"
let regex = try! NameCaptureRegex(pattern: target)
if case let .Match(parameter) = regex.match("/users/1/items/100") {
print(parameter["user_id"]) // "1"
print(parameter["item_id"]) // "100"
}
実装
public final class NameCaptureRegex {
public enum Result {
case Match([String: String])
case None
}
private var _regex: NSRegularExpression!
private var _capturedKeys: [String] = []
public init(pattern: String) throws {
let regex = try NSRegularExpression(pattern: "\\(\\?<([a-zA-Z_][0-9a-zA-Z_]+)>(.+?)\\)", options: [])
let formattedPattern = regex.stringByReplacingMatchesInString(
pattern, options: [], range: NSMakeRange(0, pattern.utf16.count), withTemplate: "($2)"
)
_capturedKeys = regex.matchesInString(pattern, options: [], range: NSMakeRange(0, pattern.utf8.count)).map {
let range = $0.rangeAtIndex(1)
let start = pattern.utf16.startIndex.advancedBy(range.location)
let end = start.advancedBy(range.length)
return String(pattern.utf16[start..<end])
}
_regex = try NSRegularExpression(pattern: formattedPattern, options: [])
}
public func match(target: String) -> Result {
let results = _regex.matchesInString(target, options: [], range: NSMakeRange(0, target.utf16.count))
if results.isEmpty {
return .None
}
var dict: [String: String] = [:]
for i in 1..<results[0].numberOfRanges {
let range = results[0].rangeAtIndex(i)
let start = target.utf16.startIndex.advancedBy(range.location)
let end = start.advancedBy(range.length)
dict[_capturedKeys[i-1]] = String(target.utf16[start..<end])
}
return .Match(dict)
}
}