既然你有了这些基础,就在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’选项。