iOS开发进阶程序员

正则表达式

2018-05-15  本文已影响117人  安静守护你

茫茫人海中,只找到了你

1. 什么是正则表达式

在某些情况下,我们总是要在某个文本中查找某些复杂规则的字符串,正则表达式就是用户描述这些规则的工具(正则表达式就是记录文本规则的代码)。

2. 举个简单的栗子

假设在一篇英文文章中,你要查找hi这个单词,这时候查找到的不仅有hi这个单词,还有类似于hiddenhight等等的,其实这不是我们想要的,我们要的仅仅就是hi这个词,而这个时候,我们就应该使用\bhi\b

  1. 元字符\b:是正则表达式规定的一个特殊代码,代表着单词的开头或结尾,即单词的分界处。需要说明的是,\b并不匹配单词分割字符(空格、标点符号、换行等),它只匹配一个位置。

  2. 元字符.:用于匹配除了换行符以外的任意字符。

  3. 元字符**既不代表字符,也不是位置,而是数量;它指定前边的内容可以连续重复使用任意次以使得整个表达式得到匹配。

回到上面的例子,如果更换需求,现在需要查找的是hi###Max,###代表的是任意字符,这时候我们就可以使用上面的三个元字符组合来查找这个特定规则的字符串了,即: \bhi\b.*\bMax\b

目前我们只知道三个元字符,如果我们知道了更多的元字符,我们就可以构造出更强大的正则表达式。

1. 元字符

从以上的例子中我们已经知道了三个元字符了,下面我就来给大家再通过栗子介绍几个常用的元字符。

代码 说明
\w 匹配字母或者数字或者下划线或者汉字
\s 匹配任意的空白符(包括空格、制表符、换行符、中文全角空格等)
\d 匹配数字
\b 匹配单词的开始或者结束
^ 匹配字符串的开始
$ 匹配字符串的结束
2. 字符转义

如果我想在文本中查找元字符本身的话,该怎么查找呢?这时候就要使用转义了

例如你要查找.,就应该使用\.。如果你要查找*,就应该使用\*。如果你要查找\,就应该使用\\

3. 重复
代码 说明
* 重复零次或者更多次
+ 重复一次或者更多次
? 重复零次或者一次
{n} 重复n次
{n,} 重复n次或者更多次
{n,m} 重复n到m次
4. 字符类

\d:代表的是0-9的数字集合,怎么可以自定义字符集呢,可以使用[]来实现

5. 分枝条件

正则表达式里的分枝条件是指有几种规则,如果满足其中任意一种规则都应该匹配,具体方法是使用|把不同的规则分隔开(分枝条件会从左到右测试执行每个条件)。

🌰

6. 分组

分组的主要目的就是重复。上面我们已经知道了怎么重复单个字符(直接在字符后面加上限定字符就可以了);但如果想要重复多个字符改怎么办呢? 这就用到了分组:使用小括号来指定子表达式然后就可以指定这个子表达式的重复次数了。

  1. 2[0-4]\d:此表达式主要是匹配200-249的数字

  2. 25[0-5]:此表达式主要是匹配250-255的数字

  3. [01]?\d\d?: 此表达式主要是匹配0-199的数字

  4. (2[0-4]\d|25[0-5]|[01]?\d\d?)\.: 此表达式为匹配到0-255的数字,并在后面跟一个.

  5. ((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}:此表达式为将上一步的表达式重复3次

至于后面的跟前面的一样,就不分析了

7. 反义
代码 说明
\W 匹配任意不是字母、数字、下划线、汉字的字符
\S 匹配任意不是空白符的字符
\D 匹配任意非数字的字符
\B 匹配不是单词开头或者结束的位置
[^x] 匹配除了x以外的任意字符
[^aeiou] 匹配除了aeiou这几个字母以外的任意字符
8. 向后引用

使用小括号指定一个子表达式后,匹配这个子表达式的文本可以在表达式或者其它程序中作进一步的处理。默认情况下,每个分组都会自动拥有一个组号,规则是:从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。
向后引用用于重复搜索前面某个分组匹配的文本。如:\1,表示分组1匹配的文本

当然也可以指定子表达式的组名。
要指定一个表达式的组名,需要使用这样的语法:(?<Name>\w+)(或者把尖括号换成',即(?'Name'\w+)),这样就把\w+的组名指定为Name了。要反向引用这个分组捕获的内容,可以使用\k<Name>,所以上一个栗子也可以写成这样纸:\b(?<Name>\w+)\b\s+\k<Name>\b

下表列出了小括号的一些常用的语法

分类 代码 说明
捕获 (exp) 匹配exp,并捕获文本到自动命名的组里
捕获 (?<name>exp) 匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name'exp)
捕获 (?:exp) 匹配exp,不捕获匹配的文本,也不给此分组分配组号
零宽断言 (?=exp) 匹配exp前面的位置
零宽断言 (?<=exp) 匹配exp后面的位置
零宽断言 (?!exp) 匹配后面跟的不是exp的位置
零宽断言 (?<!exp) 匹配前面不是exp的位置
注释 (?#comment) 这种类型的分组不对正则表达式的处理产生任何影响,用于提供注释让人阅读

我们已经讨论了前两种语法。第三个(?:exp)不会改变正则表达式的处理方式,只是这样的组匹配的内容不会像前两种那样被捕获到某个组里面,也不会拥有组号

9. 零宽断言

上表中的四个零宽断言用于查找在某些内容(但并不包括这些内容)之前或者之后的东西,也就是说它们像\b^$那样用于指定一个位置,这个位置应该满足一定的条件(即断言),因此它们也被称为零宽断言
🌰

(?=exp)也叫零宽度正预测先行断言,它断言自身出现的位置的后面能匹配表达式exp。如:\b\w+(?=ing\b),匹配ing结尾的单词的前面部分(除了ing以外的部分),如查找I'm singing while you're dancing.时,它会匹配singdanc
(?<=exp)也叫零宽度正回顾后发断言,它断言自身出现的位置的前面能匹配表达式exp。如:(?<=\bre)\w+\b会匹配re开头的单词的后半部分(除了re以外的部分),如查找reading a book时,它匹配ading
(?<=\s)\d+(?=\s)匹配以空白符间隔的数字(不包括这些空白符)

10. 负向零宽断言

(?!exp)也叫零宽度负预测先行断言,它断言此位置的后面不能匹配表达式exp
(?<!exp)也叫零宽度负回顾后发断言,它**断言此位置的前面不能匹配表达式exp
🌰

11. 注释

小括号的另一种用途是通过语法(?#comment)来包含注释。如:2[0-4]\d(?#200-249)|25[0-5](?#250-255)|[01]?\d\d?(?#0-199)

12. 贪婪与懒惰

a.*b:将会匹配最长的以a开始,以b结束的字符串。如果用此表达式搜索匹配aabab,它会匹配整个字符串aabab。这被称为贪婪匹配

有时,我们更需要懒惰匹配,也就是匹配尽可能少的字符。以上个例子为准,我们只需要在其后面加上一个问号?,这样,.*?就意味着匹配任意数量的重复、但是在能使整个匹配成功的前提下使用最少的重复

代码 说明
*? 重复任意次,但尽可能少重复
+? 重复1次或者更多次,但尽可能少重复
?? 重复0次或者1次,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复
{n,}? 重复n次以上,但尽可能少重复

以上这些关于正则表达式的介绍已经足以让我们编写、改写、读懂一些常见的正则表达式,希望以上的介绍能够帮助到你。

3. 关于正则表达式的学习

正则表达式的学习最重要的就是栗子,我们可以从不同的案例切入,理解案例并对其修改、实验(仅代表个人观点,有更好的观点可以和大家一起分享)。
关于测试:网上可以找到一些在线正则表达式测试的,童鞋们可以在那里测试验证自己写的一些表达式。

参考来源

上一篇下一篇

猜你喜欢

热点阅读