(作者:张滋,撰写时间:2019年4月8日)
首先,我们要理解正则表达式(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式 通常被用来检索、替换那些符合某个模式(规则)的文本。许多程序设计语言都支持利用正则表达式进行字符串操作。
正则表达式由普通字符以及特殊字符组成的文字模式,也是描述一种字符串匹配的模式,可以将某个字符模式与所搜索的字符串进行匹配。我们可以通过正则表达式,可以测试到字符串内是不是有我们想要的数据。正则表达式主要用来验证、搜索和替换,比如:
- 可以测试字符串内的模式。
例如,可以测试输入字符串,以查看字符串内是否出现电话号码的字符串。这被称为数据验证。 电话号码正则表达式(支持手机号码,34位区号,78位直播号码,1-4位分机号): ((\d{11})|^((\d{7,8})|(\d{4}|\d{3})(\d{7,8})|(\d{4}|\d{3})(\d{7,8})(\d{4}|\d{3}|\d{2}|\d{1})|(\d{7,8})(\d{4}|\d{3}|\d{2}|\d{1}))$) - 也可以将你需要的数据替换文本。
可以使用正则表达式来识别文档中的特定文本,完全删除该文本或者用其他文本替换它。 - 当然基于模式匹配从字符串中提取子字符串。
可以查找文档内或输入域内特定的文本。 - 纯文本看起来可能不像是个正则表达式,但它的确是。正则表达式可以包含纯文本(甚至可以只包含纯文本)。当然,像这样使用正则表达式是没什么意义,但把它作为学习正则表达式的起点还是不错的。
正则表达式中的反斜杠字符(\)指示其后跟的字符是特殊字符,或应按原义解释该字符。
所谓特殊字符,就是一些有特殊含义的字符,如上面说的"*.txt"中的*,简单的说就是表示任何字符串的意思。如果要查找文件名中有*的文件,则需要对*进行转义,即在其前加一个\。ls \*.txt。比如:
\ : 在后面带有不识别的转义字符时,与该字符匹配。
[az] :字符范围。匹配指定范围内的任意字符。
[^az] :字符范围。匹配除了小写字母以外的任意字符。
字符类
字符类与一组字符中的任何一个字符匹配。列出了字符类:
. : 匹配除换行符\n以外的任意字符。
\w :匹配字母或数字、下划线。等价于'[AZaz09_]'。
\W :匹配字母或数字、下划线。等价于'[^AZaz09_]'。
\s : 匹配任意的空白符,包括空格、制表符、换页符等等。等价于 [\f\n\r\t\v]。
\S : 匹配任意不是空白符的字符。等价于 [^\f\n\r\t\v]。
\d :匹配数字,等价于[09]。
\D : 匹配任意非数字的字符,等价于[^09]。
定位点
定位点或原子零宽度断言会使匹配成功或失败,具体取决于字符串中的当前位置,但它们不会使引擎在字符串中前进或使用字符。列出了定位点:
^ : 匹配字符串的开始
$ : 匹配字符串的结束
\b : 匹配必须出现在 \w(字母数字)和 \W(非字母数字)字符之间的边界上,或匹配单词的开始或结束。
\B : 匹配不得出现在 \b 边界上 ,或匹配不是单词开头或结束的位置
* 匹配前面的子表达式零次或多次。
. : 匹配除换行符\n以外的任意字符。
? : 重复零次或一次,等价于 {0,1},或指明一个非贪婪限定符。
| : 指明两项之间的一个选择。
2.限定符
限定符指定在输入字符串中必须存在上一个元素(可以是字符、组或字符类)的多少个实例才能出现匹配项。 限定符包括下表中列出的语言元素。
限定符用来指定正则表达式的一个给定组件必须要出现多少次才能满足匹配。有*或+或?或{n}或{n,}或{n,m}共6种。列出了限定符:
*: 重复零次或更多次,等价于{0,}
+ : 重复一次或更多次,等价于{1,}
? : 重复零次或一次,等价于 {0,1},或指明一个非贪婪限定符。
{n} : 重复n次
{n,} : 重复n次或更多次
{n,m} : 重复n到m次
*? 重复任意次,但次数尽可能少。
+? 重复1次或更多次,但次数尽可能少。
?? 重复0次或1次,但次数尽可能少。
{n,m}? 重复n到m次,但次数尽可能少。
{n,}? 重复n次以上,但次数尽可能少。
*、+和?限定符都是贪婪的,因为它们会尽可能多的匹配文字,只有在它们的后面加上一个?就可以实现非贪婪或最小匹配。前面给出的重复元字符都可以被转化为懒惰匹配模式。下面我给大家看一个例子:假如我们要匹配span标签,
<p text-indent:0pt;border-top-style:none;"><span style="color:#FF0000;font-family:'Times New Roman',宋体;font-size:12pt;">Evaluation Warning: The document was created with Spire.Doc for</span></p>
在这里我们可以看到我们贪婪是有多少个文字就会匹配多少的,因此我们在*后面加一个?就完
全可以实现非贪婪或最小匹配。贪婪有时侯能给我们方便,但是有的时候我们需要一些数据时,它因为是尽可能的匹配会给我们带来一定的麻烦的。
分组构造
分组构造描述了正则表达式的子表达式,通常用于捕获输入字符串的子字符串。我们现在已经学会重复单个字符,但是如果要重复字符串怎么做?用小括号来指定子表达式(也叫做分组),然后你就可以指定这个子表达式的重复次数了。列出了分组构造:
(exp) 匹配exp,并捕获文本到自动命名的组里。
(?<name>exp) 将匹配的子表达式exp捕获到一个命名name组中。
(?:exp) 匹配exp,不捕获匹配的文本。定义非捕获组。
(?=exp):零宽先行断言,它匹配文本中的某些位置,这些位置的后面能匹配给定的后缀exp。
(?<=exp):零宽后行断言,它匹配文本中的某些位置,这些位置的前面能给定的前缀匹配exp。
(?!exp):零宽负向先行断言,只会匹配后缀exp不存在的位置。
(?<!exp):零宽负向后行断言来查找前缀exp不存在的位置。
下面来看一下例子:
运算符的优先级
正则表达式从左到右进行计算,并遵循优先级顺序,这与算术表达式非常类似。
相同优先级的从左到右进行运算,不同优先级的运算先高后低。下表从最高到最低说明了各种正则表达式运算符的优先级顺序:
\ 转义符
(), (?:), (?=), [] 圆括号和方括号
*, +, ?, {n}, {n,}, {n,m} 限定符
^, $, \任何元字符、任何字符 定位点和序列(即:位置和顺序)
| 替换,"或"操作,字符具有高于替换运算符的优先级,使得"m|food"匹配"m"或"food"。若要匹配"mood"或"food",请使用 括号创建子表达式,从而产生"(m|f)ood"。
替换
替换是替换模式中使用的正则表达式,替换就是将表达式匹配到的字符串替换为我们想要的指定字符串,可以使用 $1、$2 等来引用对应分组的值。如下图:
正则表达式的注释:(?#)。