我使用Swift有段時間了,但最讓人郁悶的是它還不能支持正則表達式.
先要說的是,這確實是門新語言,我在網站上有注釋 a radar (rdar://17257306 for Apple folks). 如果你也認同這一觀點,請支持.
我所說的正則表達式指的是這種(Ruby代碼):
if name =~ /ski$/ puts "#{name} is probably polish"end
如果要快速查詢,可以使用=~操作符來返回匹配的結果.此外使用/pattern/syntax 形式來直接使用正則. 除了/符號需要轉義,其它符號都不受影響:
url_pattern = /^https?:////.*/
這比使用//轉義要好得多 (這在正則里很常見). 如果正則里使用了字符串,那看起來會很糟糕.這是Objective-C代碼:
regularExpressionWithPattern:@"//s+//w{4,10}//s//d+"
options:0
error:nil];
轉義每個/符號讓代碼可讀性變差. 更別提額外類的創建了. 當然,如果需要更強大的正則功能,那就得開發全套的特定實現類了. 但就一般情況來說 (在腳本語言里很常見) 有點小題大做.
Swift是怎么處理的?
Swift目前沒有提供支持正則的語法和類,所以只能使用之前提到的NSRegularExpression來實現.
但是我們可以考慮使用swift的超強操作符來實現. 考慮下面的場景:
class Regex {
let internalExpression: NSRegularExpression
let pattern: String
init(_ pattern: String) {
self.pattern = pattern
var error: NSError?
self.internalExpression = NSRegularExpression(pattern: pattern, options: .CaseInsensitive, error: &error)
}
func test(input: String) -> Bool {
let matches = self.internalExpression.matchesInString(input, options: nil, range:NSMakeRange(0, countElements(input)))
return matches.count > 0
}
}
這在使用NSRegularExpression時需要提供大量的假設驗證. 如果用另一種方法就簡單多了:
if Regex("//w{4}").test("ABCD") {
println("matches pattern")
}
我們還是無可避免的得使用字符串轉義,但比使用原生的NSRegularExpression好多了.
=~ 操作符
研究了一下 Step Christopher 的方法后,我想自己改造一下操作符功能. 看起來挺簡單的:
operator infix =~ {}
這就定義了操作符的位置,就像操作兩個元素時不是放在它們之間,而是一個元素之前或之后(就像++操作). 下面定義一個使用該操作符的函數:
func =~ (input: String, pattern: String) -> Bool {
return Regex(pattern).test(input)
}
復雜的部分是現成的,我們只需要簡單地調用.
最后,使用正則的測試結果如下:
let phoneNumber = "(800) 555-1111"
if phoneNumber =~ "(?//d{3})?//s//d{3}-//d{4}" {
println("That looks like a valid US phone number")
}
我覺得這個結果很好,如果有天Apple發現了我的這個正則實現的語法/regex/literal syntax, 我很樂意提供支持.
更新
一個樂于助人的 Hacker News評論家 指出一個更接近我想要的方向,但使用現有的API:
if let match = name.rangeOfString("ski$", options: .RegularExpressionSearch) {
println("/(name) is probably polish")
}
的確,我不知道這個,并且看起來非常有用。