怎样在Swift中使用正则表达式

本公众号内容均为本号转发,已尽可能注明出处。因未能核实来源或转发内容图片有权利瑕疵的,请及时联系本号,本号会第一时间进行修改或删除。 QQ :

正则表达式(Regular expression, regex)允许我们在几秒钟内在成千上万文档间进行复杂检索与替换,自从诞生50多年来它依旧广泛使用。

在这篇文章中,我会讲解在Swift中正则表达式的基本用法。我们会从易到难,详细讲解一些最重要的正则表达式语法,以及一些有用的扩展。

NSRegularExpression:如何在字符串中匹配正则表达式

NSRegularExpression类让我们可以用正则表达式查找替换子字符串,它可以简洁灵活地描述文本。例如,如果你想从"My name is Taylor Swift"中提取出"Taylor Swift",可以写一个匹配文本“My name is”的正则表达式,它的后面可以是任何文本,之后把它传递给NSRegularExpression类。

具体可见下面代码。注意我们要提取出的是第二范围,因为第一范围是匹配的字符串,而第二范围才是"Taylor Swift"部分。

正则表达式的详细讲解

让我们从几个简单例子开始,方便不熟悉的人了解正则表达式。正则表达式,简称regex,用于让我们在字符串中进行模糊检索。例如我们知道”cat”包含”at”,但如果我们检索所有以“at”结尾的3字母单词该怎么做呢?

正则表达式就用于解决这个问题,尽管由于Objective-C的基础,它们的语法有些不太灵巧。

1. 首先,定义你想检索的字符串:

之后创建NSRange实例来表示整个字符串的长度

这里使用utf16来避免类似表情符号等带来的问题

2. 之后使用正则表达式语法创建NSRegularExpression实例

[a-z]在正则表达式中用于指定a到z之间任意字母。实际使用中你可能会提供一个无效的正则表达式,但是这里我们有了一个硬编码的正确正则表达式,所以就不需要查找错误了。

3. 最后在创建好的正则表达式调用firstMatch(in:),输入要检索的字符串,一些特殊选项,和字符串的范围。如果字符串匹配正则表达式,就会返回数据,否则就是nil。所以如果你想检查字符串是否完全匹配,就用firstMatch(in:)的结果和nil比较:

这里必须要用到NSRange——尽管这个API是为NSString设计,和Swift衔接的不太好。Swift String Manifesto可能会替换它,但看起来还要很久。

正则表达式“[a-z]at”会成功匹配“hat”,和“cat”, “sat”, “mat”, “bat”等等——我们只要关注想匹配什么,NSRegularExpression会处理好它。

让NSRegularExpression用起来更简单

接下里会展示更多的正则表达式语法,首先来看看如何让NSRegularExpression稍微好用一些

现在我们的要3行Swift代码来匹配一个简单字符串

我们可以从多种方式改进,不过最有效的是扩展NSRegularExpression,让创建和匹配表达式更简单。

首先第一行:

我提到过,创建一个NSRegularExpression实例可能导致错误,因为可能会提供一个非法的正则表达式。比如[a-zat,忘记了]

结果就是,通常会用try!创建NSRegularExpression实例。然而这会导致lint工具(如SwiftLint)的破坏。所以好一点的方法是创建一个方便的初始化,能正确创建正则表达式,或者在开发时能生成一个断言失败。

注意:如果你的app需要用户写正则表达式,你需要使用NSRegularExpression(pattern:)初始化,这样可以更好的处理错误。

之后这些行:

第一行创建了一个包含整个字符串的NSRange,第二行则是在文本中查找first match。但这是很笨的方法,因为大多时候你想查找输入的整个字符串,用firstMatch(in:)与nil判定会弄混你的意图。

所以,用另一个扩展来替代它,它把下面代码包含在一个简单的matches()方法中。

如果你把这两个扩展合并,就可以更轻松的创建和检索正则表达式了。

我们可以进一步通过运算符重载让Swift包含的,~=,运算符适用于正则表达式:

通过上面代码,我们可以在一句话的左边使用任意字符,右边用正则表达式。

注意:创建NSRegularExpression实例会有一定消耗,所以如果你想要反复使用一个正则表达式,最好把NSRegularExpression实例保存起来。

正则表达式语法学之旅

我们已经使用了[a-z]来表示“a”到“z”之间任意字母,在正则表达式中这是一个字符类。它让你指定要匹配的一组字母,可以通过制定的字母列表匹配,或者通过一段字符范围匹配。

正则表达式范围不一定是整个字母表,你可以用[a-t] 来排除“u”到“z”之间的字母。另外,如果你想特别指定一些字母,只需要像这样单独列出它们:

正则表达式默认区分大小姐写,也就是说“Cat”和“Mat”不会在“[a-z]at”被匹配。如果你想忽略大小写,可以使用“[a-zA-Z]at”,或者创建你自己的NSRegularExpression对象,并标记.caseInsensitive

除了大小写以外,你可以通过字符类指定数字范围。最常用的是[0-9]表示任何数字,或[A-Za-z0-9]表示任何字母数字混编字符,也可以用[A-Fa-f0-9]来表示16进制数字。

如果你想匹配一个字符序列,还需要一个叫做量词(quantifier)的概念。它用于表示字符出现的数量。

最常用的是星号量词,*,意思是匹配0个或更多。量词在它们修饰的字符后出现,就像下面这样:

这句话先查找“ca”,之后是0或多个从“a”到“z”的字母,最后是“d”——它能匹配“cad”, “card”, “clamped”等等。

除了*之外,还有2个类似的量词 + 和 ? 。 + 意味着“1个或更多”,与 * 的“0个或更多”有点区别。而 ? 的意思是”0或1个”

这些量词是正则表达式基础内容,希望大家能确实理解它们的区别,比如下面3个正则表达式

ca[a-z]*d

ca[a-z]+d

ca[a-z]?d

并想想如果给出字符串“cd”或“clamped”,哪些能够匹配。

如果需要,可以用大括号 { 和 } 来更详细的指定匹配数量,比如[a-z]意味着匹配3个小写字母。

考虑一个电话号码格式比如111-1111。如果要正好匹配这个格式,用[0-9-]+是行不通的。所以我们需要用这样的正则表达式[0-9]-[0-9],即先是3个数字,之后连接号,之后4个数字。

此外还可以用大括号指定范围,它可以是有界限的或无界限的。比如[a-z]代表匹配1,2,或3个小写字母。[a-z]代表匹配3个或更多个

最后,元字符(meta-characters)是特殊字符,正则表达式中有特别的意义,在这里介绍其中几个使用最频繁的。

首先其中是最常用,也是最滥用的 . 字符。它可以匹配除了换行符以外任意一个字符。比如正则表达式c.t可以匹配“cat”,但不能匹配“cart”。如果你把 . 和 * 量词共同使用,就意味着匹配1个或多个除了换行符以外所有字符,这可能是你最常见的正则表达式了。

.* 常用的原因也显而易见:不需要具体设计一个特别的正则表达式,.* 就可以匹配几乎一切了。然而问题是,特定化本来就是正则表达式的要点之一,你可以在文本中精确查找一些字符并操作它们。而太多人完全依赖 .* ,却没有意识到这可能会给他们的表达式带来难以察觉的错误。

用前面电话号码的例子来说,我们用[0-9]-[0-9]匹配类似555-5555的电话号码。考虑到有些人会写成“555 5555”或“5555555”,我们可能就会把正则表达式条件放宽一些,改成[0-9].*[0-9]

但是这样就带来一个问题,它会匹配“123-4567”, “123-4567890”, 或 “123-456-789012345”。为了让[0-9]与[0-9]匹配上,.* 会匹配尽可能多的字符

所以这里要用字符类与量词,比如[0-9][ -]*[0-9],代表3个数字,之后0个或更多空格与连接线,之后4个数字。或者使用不包含字符类,即用它来匹配数字以外的字符,如[0-9][^0-9]+[0-9],会匹配空格,连接线,斜杠等等,而不会匹配数字。

作者:Paul Hudson

链接:https://www.hackingwithswift.com/articles/108/how-to-use-regular-expressions-in-swift

翻译:cocoachina

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180910B0A31200?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券