用脑思考,用心琢磨,用行动证实 [登录·注册]

吕滔博客

首页 开发 运维 工具 摄影

模式匹配

Swift TIP memory 发布于March 25, 2015 标签: Swift

在之前的正则表达式中,我们实现了 =~ 操作符来完成简单的正则匹配。虽然在 Swift 中没有内置的正则表达式支持,但是一个和正则匹配有些相似的特性其实是内置于 Swift 中的,那就是模式匹配。

当然,从概念上来说正则匹配只是模式匹配的一个子集,但是在 Swift 里现在的模式匹配还很初级,也很简单,只能支持最简单的相等匹配和范围匹配。在 Swift 中,使用 ~= 来表示模式匹配的操作符。如果我们看看 API 的话,可以看到这个操作符有下面几种版本:

func ~=<T : Equatable>(a: T, b: T) -> Bool

func ~=<T>(lhs: _OptionalNilComparisonType, rhs: T?) -> Bool

func ~=<I : IntervalType>(pattern: I, value: I.Bound) -> Bool

从上至下在操作符左右两边分别接收可以判等的类型,可以与 nil 比较的类型,以及一个范围输入和某个特定值,返回值很明了,都是是否匹配成功的 Bool 值。你是否有想起些什么呢..没错,就是 Swift 中非常强大的 switch,我们来看看 switch 的几种常见用法吧:

let password = "akfuv(3"
switch password {
   case "akfuv(3": println("密码通过")
   default:        println("验证失败")
}
let num: Int? = nil
switch num {
   case nil: println("没值")
   default:  println("\(num!)")
}
let x = 0.5
switch x {
   case -1.0...1.0: println("区间内")
   default: println("区间外")
}

没错,Swift 的 switch 就是使用了 ~= 操作符进行模式匹配,case 指定的模式作为左参数输入,而等待匹配的被 switch 的元素作为操作符的右侧参数。只不过这个调用是由 Swift 隐式地完成的。于是我们可以发挥想象的地方就很多了,比如在 switch 中做 case 判断的时候,我们完全可以使用我们自定义的模式匹配方法来进行判断,有时候这会让代码变得非常简洁,具有条例。我们只需要按照需求重载 ~= 操作符就行了,接下来我们通过一个使用正则表达式做匹配的例子加以说明。

首先我们要做的是重载 ~= 操作符,让它接受一个 NSRegularExpression 作为模式,去匹配输入的 String:

func ~=(pattern: NSRegularExpression, input: String) -> Bool {
    return pattern.numberOfMatchesInString(input,
        options: nil,
        range: NSRange(location: 0, length: countElements(input))) > 0
}

然后为了简便起见,我们再添加一个将字符串转换为 NSRegularExpression 的操作符 (当然也可以使用 StringLiteralConvertible,但是它不是这个 tip 的主题,在此就先不使用它了):

prefix operator ~/ {}

prefix func ~/(pattern: String) -> NSRegularExpression {
    return NSRegularExpression(pattern: pattern, options: nil, error: nil)
}

现在,我们在 case 语句里使用正则表达式的话,就可以去匹配被 switch 的字符串了:

let contact = ("http://onevcat.com", "onev@onevcat.com")
let mailRegex = 
~/"^([a-z0-9_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})$"
let siteRegex = 
~/"^(https?:\\/\\/)?([\\da-z\\.-]+)\\.([a-z\\.]{2,6})([\\/\\w \\.-]*)*\\/?$"

switch contact {
    case (siteRegex, mailRegex): println("同时拥有有效的网站和邮箱")
    case (_, mailRegex): println("只拥有有效的邮箱")
    case (siteRegex, _): println("只拥有有效的网站")
    default: println("嘛都没有")
}

// 输出
// 同时拥有网站和邮箱

相关推荐

添加新评论

网站状态

  • 栏目分类:49个
  • 发布文章:1534篇
  • 用户评论:751条
  • 开博至今:4127天

正则速查

[abc] 匹配中括号中的单个字符,如a或b或c
[^abc] 匹配除了a、b、c等字符的其他单个字符
[a-z] 匹配一个字符范围,如a到z
[a-zA-Z] 匹配一个字符范围,如a-z 或 A-Z
^ 匹配行的开始
$ 匹配行的结束
\A 匹配一个字符串的开始
\z 匹配一个字符串的结束
. 匹配任意单个字符
\s 匹配空白字符,如空格,TAB
\S 匹配非空白字符
\d 匹配一个数字
\D 匹配非数字
\w 匹配一个字母
\W 匹配非字母
\b 匹配字符边界
(...) 引用所有括号中的内容
(a|b) a或者b
a? 零个或1个a
a* 零个或多个a
a+ 1个或多个a
a{3} 3次重复的a
a{3,} 3次或3次以上重复的a
a{3,6} 3到6次重复的a

修正符

/g 查找所有可能的匹配
/i 不区分大小写
/m 多行匹配
/s 单行匹配
/x 忽略空白模式
/e 可执行模式,PHP专有
/A 强制从目标字符串开头匹配
/D 使用$限制结尾字符,则不允许结尾有换行
/U 只匹配最近的一个字符串;不重复匹配

最新回复

  • hyvm.net: 好文章,点赞
  • 新闻头条: 文章不错非常喜欢
  • 志志: 折腾了半天 感谢大神
  • Smithk464: Hey very nice blog!! Man .. Exce...
  • memory: 我已投奔phpstrom.哈哈
  • 逆风飘扬: 原来是这样!!!!!!!用惯了VS的来用zend studio没...
  • NS: 请问我这么写之后抛出了一个 javax.crypto.BadPa...
  • memory: 有内部使用的,开源的过段时间放个出来。
  • 小小: 博主 ,可有写好的
  • 111: 我看不懂唉,好多内容
  • memory: 咧,难道我手误了,回头看下官方文档去...
  • 阿东: 进入镜像的 后面 /bin/bash 是错的 你应该用的是/b...
  • memory: 帝国的安全性来说,比phpcms和dede要好的多啦.
  • 西点师培训班: 现在帝国用的少了,开源的不太会改,老被黑
  • yiyiyizoe: 谢谢~
  • memory: 不好意思呀,这个也是13年的时候,安装过淘宝的这个开源系统,做的...
  • yiyiyizoe: 实在抱歉,如果可以回答的话,只需要看这个问题:ldb支持批量导入...