wip: 正则regex
面向自己的一个文章,问题并没有完全解决,整体待补充
0 - 背景
如果是单纯使用的话,让ai写regex在给出解释自己检查一遍,感觉已经非常成熟和靠谱了,针对的是在一些字符串模拟类的题目的情况下,如果模拟要写一堆,写regex的话只有几行的情况
可能是因为初学的缘故,其实觉得写regex有点抽象,只用里面的最最基本的规则,正则的匹配可能会被我写的非常长,这个单字符串很难看出是否是合法的括号匹配,也很难看出哪些转义字符被计算机当做了一个字母
比如leetcode 65.有效数字,我把匹配串写成了
"(^(((-|\+)?[0-9]+)|((-|\+)?(([0-9]+\.?[0-9]*)|(\.[0-9]+)))|((((-|\+)?[0-9]+)|((-|\+)?(([0-9]+\.[0-9]*)|(\.[0-9]+))))(e|E)((-|\+)?[0-9]+)))$)"
, 这个能过,但前期过程中遇到了括号不匹配的报错,但实际上只是少加了一个转义的斜杠,非常难以debug,违背了减少工作量的初衷
可以直接借助在线网站(如regex101.com)来检查
python支持VERBOSE,可以编写带注释的正则表达式,例如,一个匹配电子邮件的正则表达式可以写成:
pattern = re.compile(r"""^ # 开始[\w\.-]+ # 用户名,可以包含字母、数字、点、破折号@ # @符号[\w\.-]+ # 域名\. # 点[a-zA-Z]{2,4} # 顶级域名,2到4个字母$ # 结束 """, re.VERBOSE)
但c++不行,只能写成一整个字符串的方式
普通字符串需要双反斜杠,使用原始字符串在一定程度上缓解了转义问题
1 - 基本规则
语法
-
特殊字符(需要转义)
. * + ? ^ $ | ( ) [ ] { } \
-
字符类:
[abc] 匹配a、b或c
[^abc] 匹配除a、b、c外的任何字符
[a-z] 匹配a到z之间的字符
\d 匹配数字,等同于[0-9]
\w 匹配字母、数字或下划线,等同于[a-zA-Z0-9_]
\s 匹配空白字符(空格、制表符等) -
重复
* 0次或1次
+ 1次或多次
? 0次或1次
{n} 恰好n次
{n,} 至少n次
{n,m} n到m次 -
锚点:
^ 字符串开始(或在字符类中表示取反)
$ 字符串结束 -
分组和捕获:
(exp) 匹配exp并捕获到组中
(?:exp) 匹配exp但不捕获 -
基本函数
std::regex_match() // 完全匹配 std::regex_search() // 搜索匹配 std::regex_replace() // 替换匹配内容
例子
std::string str = "hello123";
std::regex r("^[a-z]+\\d+$");
if (std::regex_match(str, r)) {// 匹配成功
}
2 - 避免编译问题
-
一点点规则开始加,中途就进行编译
-
看到c++ 20有format,其实可以把很长的规则拆成好几部分拼成一个大字符串,或者在或的规则处进行截断,分别得到匹配结果然后进行整合
std::string name = "Alice"; int unreadMessages = 3;// 使用大括号 {} 作为占位符 auto message = std::format("Hello {}, you have {} new messages.", name, unreadMessages);