-
-
Save naan/9611f3960804400a5c71 to your computer and use it in GitHub Desktop.
Ruby-ish Regex class for Swift, inspired by Matt Thompson's Swift Regex extension: https://gist.github.com/mattt/2099ee21bbfbebaa94a3
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Ruby-ish Regex class for Swift, inspired by Matt Thompson's Swift Regex extension: https://gist.github.com/mattt/2099ee21bbfbebaa94a3 | |
// | |
// Use Regex class: (returns captured string arrays instead of Bool) | |
// | |
// if m = Regexp(pattern:"tuple\\(([^,]+),\\s*([^,]+)\\s*\\)").match("tuple(1.0, 2.0)") { | |
// m[0][0] is "tuple(1.0, 2.0)" | |
// m[0][1] is "1.0" | |
// m[0][2] is "2.0" | |
// } | |
// | |
// | |
// Use literal string reps as Regex: | |
// | |
// if m = "/tuple\\(([^,]+),\\s*([^,]+)\\s*\\) # You can wirte comment with 'x' option/ix".match("Tuple(1.0, 2.0)") { | |
// m[0][0] is "tuple(1.0, 2.0)" | |
// m[0][1] is "1.0" | |
// m[0][2] is "2.0" | |
// } | |
// | |
// | |
// | |
import Foundation | |
class Regex { | |
let pattern: String | |
let options: NSRegularExpressionOptions! | |
typealias CapturedString = [[String]] | |
var m:CapturedString = [] | |
private var matcher: NSRegularExpression { | |
return NSRegularExpression(pattern: pattern, options: options, error: nil) | |
} | |
required init(pattern: String, options: NSRegularExpressionOptions = nil) { | |
self.pattern = pattern | |
self.options = options | |
} | |
func match(string:String, options: NSMatchingOptions = nil) -> CapturedString? { | |
m = [] | |
var results = self.matcher.matchesInString(string, options: options, range: NSMakeRange(0, string.utf16Count)) | |
if results.count == 0 { | |
return nil | |
} | |
else { | |
var index:Int = 0 | |
for result in results as [NSTextCheckingResult] { | |
var ret:[String] = [] | |
for var i = 0; i < result.numberOfRanges; ++i { | |
ret.append(NSString(string:string).substringWithRange(result.rangeAtIndex(i))) | |
} | |
m.append(ret) | |
} | |
return m | |
} | |
} | |
} | |
extension Regex: StringLiteralConvertible, ExtendedGraphemeClusterLiteralConvertible { | |
typealias ExtendedGraphemeClusterLiteralType = StringLiteralType | |
class func convertFromExtendedGraphemeClusterLiteral(value: ExtendedGraphemeClusterLiteralType) -> Self { | |
return self(pattern: value) | |
} | |
class func convertFromStringLiteral(value: StringLiteralType) -> Self { | |
return self(pattern: value) | |
} | |
} | |
// MARK: - | |
protocol RegularExpressionMatchable { | |
func match(regex: Regex) -> Bool | |
} | |
infix operator =~ { associativity left precedence 130 } | |
func =~<T: RegularExpressionMatchable> (left: T, right: Regex) -> Bool { | |
return left.match(right) | |
} | |
extension String { | |
func match(str:String) -> Regex.CapturedString? { | |
if let m = Regex(pattern: "^\\/(.*)\\/([imx]*)$").match(self) { | |
let pattern = m[0][1] | |
let optionsStr = m[0][2] | |
var optionsMask:UInt = 0 | |
// Is there any better way convert from NSRegularExpressionOptions <-> raw masks?? | |
// | |
//NSRegularExpressionCaseInsensitive = 1 << 0, /* Match letters in the pattern independent of case. */ | |
//NSRegularExpressionAllowCommentsAndWhitespace = 1 << 1, /* Ignore whitespace and #-prefixed comments in the pattern. */ | |
//NSRegularExpressionIgnoreMetacharacters = 1 << 2, /* Treat the entire pattern as a literal string. */ | |
//NSRegularExpressionDotMatchesLineSeparators = 1 << 3, /* Allow . to match any character, including line separators. */ | |
//NSRegularExpressionAnchorsMatchLines = 1 << 4, /* Allow ^ and $ to match the start and end of lines. */ | |
//NSRegularExpressionUseUnixLineSeparators = 1 << 5, /* Treat only \n as a line separator (otherwise, all standard line separators are used). */ | |
//NSRegularExpressionUseUnicodeWordBoundaries = 1 << 6 /* Use Unicode TR#29 to specify word boundaries (otherwise, traditional regular expression word boundaries are used). */ | |
if contains(optionsStr, "i") { | |
optionsMask |= 1 << 0 | |
} | |
if contains(optionsStr, "x") { | |
optionsMask |= 1 << 1 | |
} | |
if contains(optionsStr, "m") { | |
optionsMask |= 1 << 3 | |
} | |
let options = NSRegularExpressionOptions.fromMask(optionsMask) | |
return Regex(pattern: pattern, options: options).match(str) | |
} | |
else { | |
return nil | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment