正则表达式,意思是用来表示符合某种规则的式子,是用于匹配符合特定模式的字符串,也就是描述一类有特定规则的字符串。比如要在一篇文章中找到关于“xx大学”相关信息,如果既想找到“广州大学”的部分,也想找到“北京大学”的部分,直接搜索“大学”又可能会出现“青年大学习”这种无关信息,这时候通过正则表达式 [北|广][京|州]大学
就能查找“广州大学”和“北京大学”,当然副产品还有“广京大学”和“北州大学”。
正则表达式一般含有三种字符: 打印字符、非打印字符、特殊字符。
其中,一般打印字符和非打印字符只匹配一个字符位,如匹配 广州什么大学
的正则表达式 广州\S\S大学
中每个字符都只匹配对应的一个字符位。而特殊字符可以改变匹配的范围,从而允许匹配更多的字符位,如 广州什么什么大学
和 广州大学
都能够使用 广州(.*)大学
来匹配,这是格式化匹配的关键。
在不同系统环境中,采用的正则表达规范或许会有所不同(BREs, EREs, PREs),这里不做细究。
打印/非打印字符
通俗来说,能看到的就是打印字符(包含空格在内),不能看到的用于控制(制表符、回车符等)或筛选某一类字符的就是非打印字符,参见 ASCII 码。
\n
:换行符\r
:回车符\s
:空白符(大写\S
为非空白)\w
:字母、数字或下划线(大写\W
为非字)\d
:数字(大写\D
为非数字)
…
特殊字符(元字符)
用于限定范围、限定匹配数量、限定位置等的特殊用途字符。匹配特殊字符需要转义,比如要匹配 *
则输入 \*
。
关于捕获元和非捕获元,个人猜测联想:用于匹配的子表达式就是捕获元,匹配到了就是捕获组,捕获组会保存起来供后续使用(如反向引用),而非捕获元匹配到的非捕获组不会保存起来,可能类似于宏定义和变量的区别。
限定范围(匹配一个字符位或子表达式):
(
)
:括起来表示为子正则表达式,该子表达式可以用于其他特殊字符做进一步限定[
]
:括起来表示限定范围在…之内,比如[0-9]
、[abcd]
、[^abcd]
分别表示 0 到 9、abcd 之一、非 abcd 的任意字符。字符间默认用|
分隔,如果想用“与”可以加入&&
,“非”则表示为^
,范围表示似乎是以 ASCII 值做范围,似乎又字母大小写无关???(注意,匹配[
]
时需要转义,而匹配-
需要非常谨慎对待,因为会随语言不同有不同约定,最好就写在最后面 [.&#_-],并经过测试 ).
:匹配除换行符\n
外的任意单字符|
:二选一,匹配符号左边的字符串或符号右边的字符串
限定匹配数量(对象为前面的字符或子表达式):
+
:匹配一次或多次(贪婪)*
:匹配零次或多次(贪婪)?
:匹配零次或一次{n}
:匹配 n 次{n,}
:至少匹配 n 次{n,m}
:匹配 [n, m] 次
限定位置(表示匹配字符串出现的位置):
^
:限定在一行的开头,用在字符串开头$
:限定在一行的结尾,用在字符串结尾\b
:限定在单词边界,即字和空格之间,作为词首或尾用\B
:限定在非单词边界
非捕获元(接在表示子表达式的左括号后):
?:
:表示该子表达式不会作为捕获组保存起来?=
:正向预查,在?:
的基础上仅做预查,即匹配完后该子表达式不会被“消耗”,如 “ababa”,查ab(?:a)
得到 “aba” 一个结果,而查ab(?=a)
得到 “aba”、“aba” 两个结果?!
:反向预查,就是正向预查的子表达式匹配取反,不匹配指定子表达式,同时是非捕获元- 如:搜查开头不为
xxxx
的任意行(^(?!xxxx).*\n)+
- 如:挑出两个 [Trial complete] 及其有用信息 units_4
( \|-units_4: .*\n)(?:^(?!\[Trial complete\]).*\n)+(.*\n)\[Trial complete\]
- 如:搜查开头不为
?<!
:往前的反向预查,代表 “What’s before this is not…”
反向引用(匹配子表达式):
\1
到\99
:引用捕获组保存的结果,为动态引用,匹配的结果左到右顺序保存到 1-99 缓冲区内。如 “frisk is frisk” 可用(\w{3}) is \1
匹配 (VSCode 中反向引用为$1
)
参考资料
基础:
https://www.runoob.com/regexp/regexp-syntax.html
非捕获元:
https://segmentfault.com/a/1190000010514763
https://www.jb51.net/article/79309.htm