正则表达式(Regex, Regular Expression)是一种文本模式,使用单个字符串来描述匹配某个句法规则的字符串集合。
许多编程语言都支持利用正则表达式进行字符串匹配。许多工具软件也提供了基于正则表达式的字符串匹配能力。在软件开发方面,正则表达式的一种常见使用场景是使用正则表达式进行入参的合法校验。
起源
1951 年, 一位叫 Stephen Cole Kleene 的数学家在 McCulloch-Pitts神经网络模型基础上,发表了一篇标题为"神经网络和有限自动机中事件表示法"(Representation of Events in Nerve Nets and Finite Automata)的论文,引入了正则表达式的概念。
1968 年,Unix 之父 Ken Thompson 发表了 《正则表达式搜索算法》(Regular Expression Search Algorithm’)论文,并根据论文的算法,将正则引入到编辑器 qed ,以及之后的编辑器 ed,然后我们熟悉的文本搜索工具 grep 中。从那时起直至现在,正则表达式都是基于文本的编辑器和搜索工具中的一个重要部分。
1988 年,Larry Wall 发布了 Perl 编程语言。正则表达式功能第一次在编程语言中使用。现代编程语言如Python,Ruby,PHP,C/C++,Java等也提供了对正则表达式的支持。
语法
正则表达式是由普通字符和特殊字符(元字符)组成的文字模式。模式描述在搜索文本时要匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。
元字符
元字符只有有限个。元字符根据其作用又可细分为转义符、限定符、定位符、选择符等。接下来将一一介绍。
转义符
转义字符使用反斜线表示,用来标记特殊字符。其作用如下:
字符 | 作用 |
---|---|
\ | 基本定义是将下一个字符标记为特殊字符。注意,正则表达式对其使用扩展,转移字符的下一个字符也能表示特定语义。如\w表示匹配字母、数字、下划线。等价于 [A-Za-z0-9_] |
限定符
限定符用来指定必须要出现多少次才能满足匹配。一种由六种基本形式: {n} 、 {n,} 、 {n,m}、* 、 + 、 ? 。其作用如下:
字符 | 作用 |
---|---|
{n} | n 是一个非负整数。匹配确定的 n 次。例如,‘o{2}’ 不能匹配 “Bob” 中的 ‘o’,但是能匹配 “food” 中的两个 o。 |
{n,} | n 是一个非负整数。至少匹配n 次。例如,‘o{2,}’ 不能匹配 “Bob” 中的 ‘o’,但能匹配 “foooood” 中的所有 o。 |
{n,m} | n 和 m 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,“o{1,3}” 将匹配 “fooooood” 中的前三个 o。请注意在逗号和两个数之间不能有空格。 |
* | 匹配前面的子表达式零次或多次。例如,zo* 能匹配 “z” 以及 “zoo”。* 等价于{0,} |
+ | 匹配前面的子表达式一次或多次。例如,zo* 能匹配 “zo” 以及 “zoo”。+ 等价于{1,} |
? | 匹配前面的子表达式零次或一次。例如,zo? 能匹配 “z” 、 “zo”。? 等价于 {0,1} |
定位符
定位符用来描述字符串或单词的边界。其中,^ 和 $ 分别指字符串的开始与结束,\b 描述单词的前或后边界,\B 表示非单词边界。具体描述如下:
字符 | 作用 |
---|---|
^ | 匹配输入字符串的开始位置。 |
$ | 匹配输入字符串的结束位置。 |
\b | 匹配一个单词边界,即字与空格间的位置。 |
\B | 非单词边界匹配。 |
这里比较难理解的就是\b和\B。\B是\b的反义,这里重点说明下\b。假设有一段话:“Hello World”,则对于正则表达式"\b/g"将匹配到“H、o、W、d”四个字符。更多示例可参考链接
圆括号
正则表达式引入圆括号实现分组功能。针对不同的应用场景,可以选择相应的模式。具体模式说明如下:
字符 | 作用 |
---|---|
(pattern) | 匹配 pattern 并获取这一匹配。所获取的匹配可以从产生的 Matches 集合得到。 |
(?:pattern) | 匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。 |
(?=pattern) | 正向肯定预查(look ahead positive assert),在任何匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,“Windows(?=95|98|NT|2000)“能匹配"Windows2000"中的"Windows”,但不能匹配"Windows3.1"中的"Windows”。这里的正向是指向右查找。 |
(?!pattern) | 正向否定预查(look ahead negative assert),在任何不匹配pattern的字符串开始处匹配查找字符串。与(?=pattern)一样,(?!pattern)也是一个非获取匹配。例如"Windows(?!95|98|NT|2000)“能匹配"Windows3.1"中的"Windows”,但不能匹配"Windows2000"中的"Windows"。 |
(?<=pattern) | 反向肯定预查(look behind positive assert),与正向肯定预查类似,只是方向相反。例如,"(?<=95|98|NT|2000)Windows"能匹配"2000Windows"中的"Windows",但不能匹配"3.1Windows"中的"Windows"。 |
(?<!pattern) | 反向否定预查(look behind negative assert),反向否定预查,与正向否定预查类似,只是方向相反。例如"(?<!95|98|NT|2000)Windows"能匹配"3.1Windows"中的"Windows",但不能匹配"2000Windows"中的"Windows"。 |
方括号
正则表达式引入方括号实现多匹配功能。针对不同的应用场景,可以选择相应的模式。具体模式说明如下:
字符 | 作用 |
---|---|
[xyz] | 匹配字符集合。匹配所包含的元素中任意一个字符。例如, ‘[abc]’ 可以匹配 “plain” 中的 ‘a’。 |
[^xyz] | 非匹配字符集合。匹配未包含的任意字符。例如, ‘[^abc]’ 可以匹配 “plain” 中的’p’、‘l’、‘i’、‘n’。 |
[a-z] | 匹配字符范围。匹配指定范围内的任意字符。例如,’[a-z]’ 可以匹配 ‘a’ 到 ‘z’ 范围内的任意小写字母字符。 |
[^a-z] | 非匹配字符范围。匹配任何不在指定范围内的任意字符。例如,’[^a-z]’ 可以匹配任何不在 ‘a’ 到 ‘z’ 范围内的任意字符。 |
修饰符
修饰符也称为标记,正则表达式的修饰符用于指定额外的匹配策略。修饰符不写在正则表达式里,修饰符位于表达式之外,格式如下:
/pattern/flags
常用的修饰符的含义如下:
修饰符 | 作用 |
---|---|
i | i表示ignore。将匹配设置为不区分大小写,搜索时不区分大小写: A 和 a 没有区别。 |
g | g表示global。将匹配设置为全局匹配,查找所有的匹配项。 |
示例
这里给出java使用示例。
// 使用正则相关类库
public boolean isFind(String patternStr, String str) {
Pattern pattern = Pattern.compile(patternStr);
Matcher matcher = pattern.matcher(str);
return matcher.find();
}
参考
https://www.runoob.com/regexp/regexp-tutorial.html 正则表达式 - 教程
https://www.rand.org/content/dam/rand/pubs/research_memoranda/2008/RM704.pdf Representation of Events in Nerve Nets and Finite Automata
https://cloud.tencent.com/developer/article/1914673 梳理正则表达式发展史
https://swtch.com/~rsc/talks/regexp.pdf Implementing Regular Expressions
https://perldoc.perl.org/perlhist perl 语言历史
https://regexper.com/ 正则表达式可视化
https://c.runoob.com/front-end/854/ 正则表达式在线测试
https://www.zhihu.com/question/48219401 如何学会正则表达式
https://github.com/ziishaned/learn-regex 学习正则
https://segmentfault.com/a/1190000013084624 正则表达式中[\b]和\b和\B的区别及匹配分析思路
https://zhuanlan.zhihu.com/p/27355118 正则表达式括号的作用