有些人说: 遇到问题,明白了。我要用 NSRegularExpression: 正则表达式, 现在有三个问题
编程世界里, 正则表达式应用广泛。 有些觉得这个十分难以理解, 符号密集。 更多的程序员觉得,正则表达式是代码的基础 ,是一个笑话。
有些程序员觉得,正则表达式,真是轻便,有强大。没有工具库这样通用的神器的人,不知道他们怎么工作的。
首先,我们都认为,Cocoa 在NSRegularExpression中,封装了你不曾见识过的 强大的正则表达式。
不行吗?我们从这个HTML片段中提取链接,先用Ruby
两三行程序,看你怎么数了。
还行吧,现在试试在Swift 中使用 NSRegularExpression 提取链接
不要BS
这篇文章,不会深入浅出地讲解正则表达式本身。你可能需要学习通配符,反向引用 ,先行断言等等。
阅读苹果的NSRegularExpression,NSTextCheckingResult及其相关联的文档,你会明了Swift 中的正则表达式。
NSString Methods , NSString 方法
在 Cocoa 框架中对正则表达式最简单的使用,当然是 跳过NSRegularExpression。
NSString 的 range(of:...) 方法,给出.regularExpression 选项时,即可切换到正则表达式模式,
然后 轻量级的搜索可以这么写:
Swift
@H_403_9@let source = "For NSSet and NSDictionary,the breaking..." // 匹配一切Cocoa 中的类型 // UIButton,NSCharacterSet,NSURLSession,等等 let typePattern = "[A-Z]{3,}[A-Za-z0-9]+" if let typeRange = source.range(of: typePattern,options: .regularExpression) { print("First type: \(source[typeRange])") // NSSet }Objective-C
@H_403_9@NSString *source = @"For NSSet and NSDictionary,the breaking..."; // 匹配一切Cocoa 中的类型 // UIButton,等等 NSString *typePattern = @"[A-Z]{3,}[A-Za-z0-9]+"; NSRange typeRange = [source rangeOfString:typePattern options:NSRegularExpressionSearch]; if (typeRange.location != NSNotFound) { NSLog(@"First type: %@",[source substringWithRange:typeRange]); // NSSet }同样的选项,使用replacingOccurrences(of:with:...)方法,轻松实现替换,
看,我们怎样通过这种巧妙的方法,在文本中用Markdown风格的倒引号,把每一个类型名括起来。
Swift
@H_403_9@let markedUpSource = source.replacingOccurrences(of: typePattern,with: "`$0`",options: .regularExpression) print(markedUpSource) //例句: "For `NSSet` and `NSDictionary`,the breaking...""Objective-C
@H_403_9@NSString *markedUpSource = [source stringByReplacingOccurrencesOfString:typePattern withString:@"`$0`" options:NSRegularExpressionSearch range:NSMakeRange(0,source.length)]; NSLog(@"%@",markedUpSource); // 例句: "For `NSSet` and `NSDictionary`,the breaking...""在替换模版中,这种运用正则表达式的途径,甚至可以处理小群的引用。
变形出又快又黑的儿童黑话
Swift
@H_403_9@let ourcesay = source.replacingOccurrences( of: "([bcdfghjklmnpqrstvwxyz]*)([a-z]+)",with: "$2$1ay",options: [.regularExpression,.caseInsensitive]) print(ourcesay) // "orFay etNSSay anday ictionaryNSDay,ethay eakingbray..." 故意颠倒英语字母顺序拼凑而成的行话;儿童黑话Objective-C
@H_403_9@NSString *ourcesay = [source stringByReplacingOccurrencesOfString:@"([bcdfghjklmnpqrstvwxyz]*)([a-z]+)" withString:@"$2$1ay" options:NSRegularExpressionSearch | NSCaseInsensitiveSearch range:NSMakeRange(0,source.length)]; NSLog(@"%@",ourcesay); // "orFay etNSSay anday ictionaryNSDay,ethay eakingbray..." 故意颠倒英语字母顺序拼凑而成的行话;儿童黑话这两个方法用来处理许多需要使用正则表达式的情况,足够了。我们需要NSRegularExpression本身来处理,更复杂的情况。
我们先用Swift 区分较复杂的数据。
NSRange and Swift,Swift 中的 NSRange
不同于Foundation框架下的NSString,Swift 字符串的字符与子串,更同意理解,看起来更复合。
Swift的标准库String的数据有 四种不同的编码方式
可以快速地通过字符、 统一码标量值、UTF-8 编码单元 或者 UTF-16编码单元 ,访问字符串里面的数据。
这与NSRegularExpression,有什么关系?
许多 NSRegularExpression 方法使用NSRange , NSTextCheckingResult的实例,来存取匹配的数据。
同样的, NSRange 使用两个整型参数 location 和 length,
但是String中没有使用整型参数作为索引的方式。
困惑吧! 心累吧!
继续干!
一切都不是,表面看起来毫无关联的。
Swift 中的 String,明确就是 与Foundation框架下的 NSString 的APIs ,具有互操作性。
只要引入了Foundation框架,就可以直接以utf16的形式,直接用整型创建新的索引。
请记住, 对String扩展一下,就能轻松地区分开Swift、 Objective-C的 NSRange
@H_403_9@extension String { /// 有一个 `NSRange` 反射出这个字符串的全部范围 var nsrange: NSRange { return NSRange(location: 0,length: utf16.count) } /// 返回给定范围的子串 /// 如果该范围,转换失败,返回nil func substring(with nsrange: NSRange) -> String? { guard let range = nsrange.toRange() else { return nil } let start = UTF16Index(range.lowerBound) let end = UTF16Index(range.upperBound) return String(utf16[start..<end]) } /// 返回与 给定范围相同的范围 /// 如果该范围,转换失败,返回nil func range(from nsrange: NSRange) -> Range<Index>? { guard let range = nsrange.toRange() else { return nil } let utf16Start = UTF16Index(range.lowerBound) let utf16End = UTF16Index(range.upperBound) guard let start = Index(utf16Start,within: self),let end = Index(utf16End,within: self) else { return nil } return start..<end } }下一结中,我们将会讲解这些,我们会明了NSRegularExpression 的用途
NSRegularExpression & NSTextCheckingResult NSRegularExpression 与 NSTextCheckingResult