正则表达式 看完这些就够了

又好久没写文章了,最近攒了几个话题,还没来得及写,在年末的最后一天,还是要写一篇,跨年啦~一篇文章写到2020年。不抛弃不放弃,过几年再看看现在写的,就如同我现在看之前写的。还有就是刚刚研究了一下如何做个标题党,来了一个(哈哈)。废话不多说,开始正题。

我们都会或多或是的用到过正则匹配,大家真的清楚用的是哪种正则吗?各种语言的正则又有哪些异同呢?


目录

1  各种各样的正则表达式

2  boost::regex 的简单介绍

2.1 Perl 正则表达式

2.1.1  基本字符含义

2.1.2  [贪婪模式] 和 [非贪婪模式]

2.1.3 [阻止回溯匹配(Possessive repeats)] 

2.1.4 [反向引用(回引 back references)]

2.1.5  [替换 alternation]

2.1.6  [字符集合]

2.1.7  [取反]

2.1.8  [字符类]

2.1.9 [单词边界]

2.2 POSIX extended 正则表达式

2.3 POSIX Basic 正则表达式

2.4 boost 正则操作主要使用的接口

3  std::regex 的简单介绍

4 boost::regex 和 std::regex 的性能对比

5 谈谈其他语言的 regex

6 正则表达式工具

6.1 正则表达式在线分析工具regexper

6.2 perl在线正则测试工具

6.3  正则表达式在线测试工具

6.4  各种语言正则的写法工具


1  各种各样的正则表达式

翻看boost, cplusplus的官方文档可以看出来,主要有三种正则表达式:基本的正则表达式(Basic RegEx),扩展的正则表达式(Extended RegEx),Perl正则表达式(Perl RegEx).
 
图 1  boost 库中主要支持的三种正则表达式。boost::regex 默认使用的是 Perl 正则表达式。
正则表达式 看完这些就够了
 
图2  c++标准库中主要支持的正则表达式。std::regex 默认使用使用的是 ECMAScript 正则表达式(后面再来讲讲ECMAScript是什么)。
 
正则表达式 看完这些就够了
 

2  boost::regex 的简单介绍

boost::regex e1(my_expression); 默认设置的式boost::regex::perl,perl 和其他正则类型比较起来支持的内容更多,兼容性也就更好。
 

2.1 Perl 正则表达式

2.1.1  基本字符含义

除了下面的字符以外,其他字符都和自己匹配,
. [ { } ( ) \ * + ? | ^ $
 
.  表示任意一个字符
^ 匹配开头字符
$ 匹配结尾字符
() 子表达式,可以把子表达式作为一个单元进行正则处理。
这里有个副作用,在结果中会有匹配子串的字段,小括号里面用 ?:  可以屏蔽捕获。例如(?:ab)+ 
 
*匹配前面的原子(preceding atom)0次或多次
+匹配前面的原子(preceding atom)1次或多次
?匹配前面的原子(preceding atom)0次或1次
 
a{n} 匹配a字符n次
a{n,} 匹配a字符n次或更多次
a{n, m} 匹配a字符n到m次
 

2.1.2  [贪婪模式] 和 [非贪婪模式]

贪婪模式会尽可能多的匹配,如 字符串abcdc, 正则a*c,会匹配到abcdc,而非贪婪匹配结果为abc,匹配到结果就好,不需要匹配的那么多。非贪婪模式需要添加 ?表示,如a*?c.
*?表示匹配前面的原子0次或多次,最短匹配
+?表示匹配前面的原子1次或多次,最短匹配
??表示匹配前面的原子0次或1次,最短匹配
{n,}? 匹配前面的原子n次或多次,最短匹配
{n, m}? 匹配n到m次,最短匹配
 

2.1.3 [阻止回溯匹配(Possessive repeats)] 

默认,如果剩下的表达式匹配失败了,那么是允许回溯,再次进行匹配的,但是可以阻止回溯。
下面的 加号 + 表示不回溯
*+表示匹配前面的原子0次或多次,不允许回溯
++表示匹配前面的原子1次或多次,不允许回溯
?+表示匹配前面的原子0次或1次,不允许回溯
{n,}+ 匹配前面的原子n次或多次,不允许回溯
{n, m}+ 匹配n到m次,不允许回溯
 
 

2.1.4 [反向引用(回引 back references)]

就是用 \n , n为1-9,引用当前正则前面的子表达式。
例如 ^(a*)[^a]*\1$,这里的 \1 表示引用该正则表达式中第一个子表达式 (*a). 也可以使用 \g1 等价于 \1.  (这里需要注意的是,匹配字符串aaabbaaa, 但是不会匹配aaabba,\1位置的子串要和引用的第一个子表达式所匹配的子串一致,才能匹配。
\g{n}  这里的n可以大于9.
\g-1  引用最后一个子表达式。
\g{-2} 引用倒数第二个子表达式。?
\g{one} 或 \k<one>引用名为“one”的子表达式。
子表达式命名方式:(?<name>expression) 或 (?'name'expression)
 

2.1.5  [替换 alternation]

expression1 | expression2  或 (expression1 | expression2 ) 表示 expression1 或 expression2.
注意:不允许其中一个表达式是空的,如 |abc, expression1为空,这样的表示方法不被允许,可以转换为 (?:)|abc 或是 (?:abc)??
 

2.1.6  [字符集合]

用 [] 表示字符集合,可以匹配其中的任意一个字符,[]后面可以配合*,+,?,{n, m} 使用,表示匹配几次。 
单一字符表示:[abc]
字符序列表示:[a-z]
 

2.1.7  [取反]

用^表示取反,如[^a-c],匹配不在a-c范围的任意字符。
 

2.1.8  [字符类]

用 [[:name:]],匹配字符类(name字符类名),如[[:lower:]] (等价于\L)匹配小写字符。
下面列举了boost.regex 支持的字符类。
 

2.1.9 [单词边界]

< 匹配单词开始
> 匹配单词结尾
\b 匹配单词开始和结尾,如\bword\b
\B 匹配非单词的边界,也就是匹配符号和符号,单词和单词的边界,不匹配单词和符号的边界。
 
还有一些正则,用的不多,这里就不介绍了。。。
 

2.2 POSIX extended 正则表达式

boost::regex e1(my_expression, boost::regex::extended);
大部分用法和 perf 正则是一样的,通过看文档没有perf支持的丰富,不过常用的基本能够满足。
区别:  \< 匹配单词开始  \> 匹配单词结尾
 

2.3 POSIX Basic 正则表达式

boost::regex e1(my_expression, boost::regex::basic);
和perf,POSIX extended 比较起来 支持的正则表达更少了。
基本支持:.[\*^$ 这几个字符表达特殊含义,其他的字符都与自身匹配。
子表达式需要用\( , \),小括号前加\.
 

2.4 boost 正则操作主要使用的接口

#include <boost/regex.hpp>
 
regex_match 需要字符串和正则表达式完全匹配,主要用于验证数据输入。
regex_search 查找字符串和正则表达式匹配的部分,不要求完全匹配。
regex_replace 对所有正则匹配的位置进行替换。
 
 

3  std::regex 的简单介绍

标准库的正则和boost::perl的正则基本兼容,这里不再一一列举。
主要的函数接口也同boost,有regex_match, regex_search, regex_replace。
 

4 boost::regex 和 std::regex 的性能对比

这里有PCRE,boost, std 的性能对比。
 
 

5 谈谈其他语言的 regex

PHP的正则叫做PCRE ,有一些和perl不同之处,具体见: https://www.php.net/manual/zh/reference.pcre.pattern.differences.php
 

6 正则表达式工具

6.1 正则表达式在线分析工具regexper

这个是 支持JavaScript-style正则表达式的可视化分析工具,除了js外的正则规则,像子串命名,反向引用等不支持。
从他的gitlib( https://gitlab.com/javallone/regexper-static)中可以看出也有人提出支持其他的正则类型的需求,不过作者的初衷还是只支持js的正则,不过js的正则常用的正则都兼容,也是基本够用的。
 
正则表达式 看完这些就够了
 

6.2 perl在线正则测试工具

正则表达式 看完这些就够了

 

6.3  正则表达式在线测试工具

不过这个工具自测有些特别的perl 并不支持, perl的还是使用第2个工具比较好。
正则表达式 看完这些就够了

 

6.4  各种语言正则的写法工具

支持js, php, go,rb,py, java.
 
正则表达式 看完这些就够了

 

参考资料: