正则表达式 看完这些就够了
又好久没写文章了,最近攒了几个话题,还没来得及写,在年末的最后一天,还是要写一篇,跨年啦~一篇文章写到2020年。不抛弃不放弃,过几年再看看现在写的,就如同我现在看之前写的。还有就是刚刚研究了一下如何做个标题党,来了一个(哈哈)。废话不多说,开始正题。
我们都会或多或是的用到过正则匹配,大家真的清楚用的是哪种正则吗?各种语言的正则又有哪些异同呢?
目录
2.1.3 [阻止回溯匹配(Possessive repeats)]
2.1.4 [反向引用(回引 back references)]
4 boost::regex 和 std::regex 的性能对比
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.
参考资料:
boost::regex :https://www.boost.org/doc/libs/1_72_0/libs/regex/doc/html/boost_regex/syntax/perl_syntax.html
c++ std::regex : http://www.cplusplus.com/reference/regex/basic_regex/basic_regex/