Swift中使用Regex的一些方法_Swift

來源:互聯網
上載者:User

我使用Swift有段時間了,但最讓人鬱悶的是它還不能支援Regex.

先要說的是,這確實是門新語言,我在網站上有注釋 a radar (rdar://17257306 for Apple folks). 如果你也認同這一觀點,請支援.

我所說的Regex指的是這種(Ruby代碼):
 

if name =~ /ski$/ puts "#{name} is probably polish"end

如果要快速查詢,可以使用=~操作符來返回匹配的結果.此外使用/pattern/syntax 形式來直接使用正則. 除了/符號需要轉義,其它符號都不受影響:

 url_pattern = /^https?:\/\/.*/


這比使用\\轉義要好得多 (這在正則裡很常見). 如果正則裡使用了字串,那看起來會很糟糕.這是Objective-C代碼:
 

複製代碼 代碼如下:
NSRegularExpression *regex = [NSRegularExpression
  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")
}

的確,我不知道這個,並且看起來非常有用。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.