Skip to content

Instantly share code, notes, and snippets.

@naan
Forked from mattt/regex.swift
Last active August 29, 2015 14:05
Show Gist options
  • Save naan/9611f3960804400a5c71 to your computer and use it in GitHub Desktop.
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
//
// 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