正则表达式之语法
之前使用正则表达式,总对一部分正则语法模棱两可。这周末看了《正则表达式必知必会》,一本100来页的小工具书,非常实用,系统地梳理了正则表达式的语法。本文主要围绕这本书,从易到难介绍正则的使用,用于帮我自己梳理思路。
匹配单个字符
1、直接某个字符匹配该字符
2、使用.
匹配任意一个字符
3、使用\
匹配元字符,比如\.
、 \\
匹配一组字符
1、在[]
中放置一个字符集合,匹配其中的一个,比如[ns]
,匹配n
或者s
2、在[]
中放置一个范围,匹配其中的一个,比如[A-Za-z0-9]
,匹配数字或者字母
3、在[]
中可以使用取非操作,比如[^0-9]
,表示非数字字符
使用元字符
1、可以通过增加\
来匹配元字符,比如\[
,\]
,\.
,\\
2、匹配空白字符,即匹配各种控制字符,比如换行(\n),回车(\r)、换页(\f),制表符(\t),垂直制表(\v)等。比较常见是使用\r\n
匹配windows系统的换行,Linux系统的换行是\n
3、匹配字符类别
元字符 | 匹配说明 |
---|---|
\d | 数字,等价于[0-9] |
\D | 非数字,等价于[^0-9] |
\w | 数字字母加下划线,等价于[a-zA-Z0-9_] |
\W | 非数字字母加下划线,等价于[^a-zA-Z0-9_] |
\s | 空白字符,等价于[\f\n\r\t\v] |
\S | 非空白字符,等价于[^\f\n\r\t\v] |
POSIX字符集 | 比如[[:xdigit:]]匹配十六进制数字 |
重复匹配
1、重复规则
规则 | 匹配说明 |
---|---|
+ | 一个或多个,比如\w+ ,表示至少一个字母数字下划线类型字符 |
* | 零个或多个 |
? | 零个或一个 |
{3} | 指定个数 (注意,这里的数字只是举例,下面出现的集合例子也用一个数字举例) |
{3,5} | 指定区间,可以是开区间,比如{3, } ,表示大于等于3 |
2、贪婪型和懒惰型
重复匹配中的+
,*
,{a,}
(注意,是开区间),这三个模式都没有一个上限值,所以存在贪婪行为和懒惰行为的区分,默认都是贪婪行为。
二者的区别在于,贪婪行为会尽可能的匹配最长的结果,而懒惰行为则会尽量匹配最小的结果。
为了将以上三种重复匹配切换为懒惰模式,需要做相应转换。
贪婪 | 懒惰 |
---|---|
+ | +? |
* | *? |
{3,} | {3,}? |
位置匹配
1、单词边界,可以使用\bcat\b
这样的模式,匹配单词cat
,匹配到的字符串必须是一个独立的单词,也就是两侧都是空格,而不能是某个单词的一部分。顾名思义,\bcat
和’cat\b’分别表示以’cat’开头和结尾的单词。
2、非单词边界,使用\B-\B
将会匹配on your color - coded
中的-
。(这个用法我还存在疑问)
3、字符串开头匹配,在正则开头加上^
,字符串结尾匹配,在正则表达式末尾加上¥
。^.*$
可以表示任意字符。
4、分行匹配,在模式开头启用(?m)
将会使得^
和$
以行为单位进行处理。
子表达式
前面我们学习的匹配字符多次重复的语法,都是针对单个字符的重复,而子表达式是为了处理多个字符的重复,多个字符组成一个子表达式。只需用()
包围起来即可成为一个子表达式,包围的内容可以是一个普通字符串,也可以是一个正则表达式。
子表达式除了用于表达字符串的重复,还用于|
操作符两侧的条件做出准确的定义,最好对复杂的条件使用子表达式
另外,子表达式支持嵌套使用。
回溯引用:前后一致匹配
可以使用\1
,\2
,\3
这样的格式,代表一个正则表达式中的第一,二,三个子表达式,这就是回溯引用的意思。
比如以下例子
1 | <[hH]([1-6])>.*?</[Hh]\1> |
以上例子,会匹配到所有正确的HTML的标题标签,而不会匹配到最后一行错误的<H2>This is not valid line</H3>
回溯引用除了用于文本匹配,也可以用于文本替换,关于文本替换,这里就不列举了,推荐参考原书。
前后查找
前后查找是指对某一些位置的前后进行查找,比如,查找html中<Title>
和</Title>
中间的标题内容,而且匹配结果不带上<Title>
和</Title>
标签。
向前匹配,使用(?=)
,比如
1 | .*(?=:) |
向后匹配,使用(?<=)
,比如
1 | (?<=\$)[0-9.]+ |
向前查找和向后查找可以结合使用,这个用法用法在解析HTML时很使用,比如提取<Title>
和</Title>
中间的内容。
向前查找和向后查找也可以取非,意义在于,不用特定字符开始或不用特定字符结尾,同样的,这些特定字符不在最终匹配结果中。向前查找取非:(?!)
,向后查找取非:(?<!)
嵌入条件
嵌入条件用于两种地方,回溯引用和前后查找。
以下是回溯引用嵌入条件的一个例子
1 | (\()?\d{3}(?(1)\)|-)\d{3}-\d{4} |
其中精华在于这一段,(?(1)xx|yy)
,如果回溯引用1成立,则执行xx匹配,否则执行yy匹配
以下是前后查找嵌入条件的一个例子,
1 | \d{5}(?(?=-)-\d{4}) |
如果向前查找(?=-)
成立,则需要继续匹配-\d{4}
书的末尾,提到了各个语言的正则表达式解析引擎存在一些大大小小的区别。
最后,推荐一个在线正则匹配的网站,https://regex101.com/
好,到此为止,介绍忘了正则的基本语法,下一节会介绍正则的解析引擎,DFA和NFA,敬请期待。