既然你有了這些基礎,就在APP中應用正則表達式吧。
如果你還沒有這樣做,下載 starter project 開始本教程吧。下載下來,用Xcode打開并運行它。
APP的UI部分已經完成了大部分,但這個APP的核心功能依賴與正則表達式,這個還沒有…!你的任務就是添加正則表達式來時這個APP更出色。
下面所視的幾個截圖的例子展示了這個應用的內容:
這個簡單的應用涵蓋兩個正則表達式的通用用例:
1.執行搜索:高亮顯示搜索和替換
2.驗證用戶輸入
這就開始直接使用正則表達式:文本搜索
- /Search( and replace)?/
這是一個搜索/替換的簡單功能的概述:
搜索視圖控制器SearchViewController 有一個只讀的UITextView,其內容是《傲慢與偏見》的一個片段。
navigation bar包含一個搜索按鈕,點擊會呈現一個模態的SearchOptionsViewController。
用戶輸入一些信息并點擊“Search”按鈕。
APP會隱藏這個search view 并高亮顯示textview中所有匹配的內容。
如果用戶選擇了SearchOptionsViewController中的“Replace”選項,APP會執行搜索并替換文本中所有匹配的內容,不再是高亮顯示結果。
Note:你的APP會用到UITextView的NSAttributedString屬性來高亮顯示搜索的結果。更多這方面的內容請參考 iOS 6 by Tutorials的第15章--“What’s New with Attributed Strings”。
你也可以用text kit來實現高亮的功能。確保找到Text Kit Tutorial in Swift 來查看更多內容。
還有一個“Bookmark”按鈕,允許用戶高亮顯示文本中的日期,時間,位置。為簡單起見,不會涵蓋文本中出現的各種格式的日期時間位置。在教程的結尾你可以實現這個高亮功能。
開始實現這個功能的第一步是跳轉到標準字符串正則表達式的NSRegularExpression對象。
打開SearchOptionsViewController.swift。SearchViewController模態顯示這個view controller,且允許用戶鍵入他們的搜索條件,也可以指定是否區分大小寫。
看一下文件頭部的SearchOptions結構體,SearchOptions是一個封裝了用戶搜索選項的簡答結構體。代碼傳遞SearchOptions的一個實例給SearchViewController。它用這種方式很好的構造一個合適的NSRegularExpression,你可以通過運用擴展自定義的NSRegularExpression來實現。
選擇File > New > File… 選擇Swift File,命名為RegexHelpers.swift。打開新建的文件并添加如下代碼:
extension NSRegularExpression {
convenience init?(options: SearchOptions) {
let searchString = options.searchString
let isCaseSensitive = options.matchCase
let isWholeWords = options.wholeWords
let regexOption: NSRegularExpressionOptions = (isCaseSensitive) ? .allZeros : .CaseInsensitive
let pattern = (isWholeWords) ? "\\b\(searchString)\\b" : searchString
self.init(pattern: pattern, options: regexOption, error: nil)
}
}
代碼為NSRegularExpression增加了一個便利構造方法。它通過SearchOptions實例的不同設置來做一些正確的配置。
當用戶請求一個不區分大小寫的搜索,正則表達式使用.CaseInsensitive的CaseInsensitiveNSRegularExpressionOptions值。NSRegularExpression默認是區分大小寫的,這個例子中,你使用的是更有好的不區分大小寫。
如果用戶請求一個完整的單詞,APP把正則表達式包含在\b字符組之內。在單詞邊界字符組中放入\b,因此,搜索模式之前和之后加上\b就會返回一個完整的單詞搜索(舉例來說,模式“\bcat\b”只會匹配單詞“cat”,而不會匹配“catch”)。
如果以任何理由都不能創建NSRegularExpression,構造函數就會失敗并返回nil。既然你有了NSRegularExpression對象,你就能伴隨著其他操作來匹配文本了。
打開SearchViewController.swift,找到searchForText,用下面的代碼替換它。
func searchForText(searchText: String, replaceWith replacementText: String, inTextView textView: UITextView) {
let beforeText = textView.text
let range = NSMakeRange(0, countElements(beforeText))
if let regex = NSRegularExpression(options: self.searchOptions!) {
let afterText = regex.stringByReplacingMatchesInString(beforeText, options: .allZeros, range: range, withTemplate: replacementText)
textView.text = afterText
}
}
首先,這個方法捕獲UITextView中得當前文本,并計算文本的長度。可能會把正則表達式應用在文本的一個子集上,所以你需要指定一個范圍。這種情況下,你要用字符串的整個長度才能保證正則表達式被運用在整個文本上。
不可思議的事發生在調用stringByReplacingMatchesInString的時候。這個方法返回一個新字符串并沒有改變舊字符串。然后,這個方法給UITextView設置這個新字符串,所以用戶看到了正確的結果。
繼續留在SearchViewController,找到highlightText,用下面的代碼替換它。
func highlightText(searchText: String, inTextView textView: UITextView) {
// 1
let attributedText = textView.attributedText.mutableCopy() as NSMutableAttributedString
// 2
let attributedTextRange = NSMakeRange(0, attributedText.length)
attributedText.removeAttribute(NSBackgroundColorAttributeName, range: attributedTextRange)
// 3
if let regex = NSRegularExpression(options: self.searchOptions!) {
let range = NSMakeRange(0, countElements(textView.text))
let matches = regex.matchesInString(textView.text, options: .allZeros, range: range)
// 4
for match in matches as [NSTextCheckingResult] {
let matchRange = match.range
attributedText.addAttribute(NSBackgroundColorAttributeName, value: UIColor.yellowColor(), range: matchRange)
}
}
// 5
textView.attributedText = attributedText.copy() as NSAttributedString
}
這兒就一步一步的解釋上面的代碼:
1.首先,得到一個textview的attributedText的可變拷貝,
2.然后,創建一個整個文本長度的NSRange,并刪除已經有背景色的文本的背景色,
3.正如找到和替換,緊接著用你的便利構造方法創建一個正則表達式,獲取一個存放正則表達式與textview中文本匹配的所有匹配項的數組。
- 輪詢每一個匹配項(把它們轉換成NSTextCheckingResult對象),并為每一項添加黃色背景。
5.最后,用高亮的結果更新UITextView。
編譯和運行你的APP,試著搜索一些不同的單詞和詞組!整個文本的匹配項都會高亮顯示,就像下面的圖片所示:
試著使用不同的選項(options)搜索單詞“the”看看效果。注意,例如,當搜索整個單詞時,‘them’中得‘the’不會高亮顯示。
再者,測試一下搜索和替換功能,看看你的文本字符串是怎樣如期替換的,試一下’match case‘和‘whole words’選項。