热线电话:0755-23712116
邮箱:contact@shuangyi-tech.com
地址:深圳市宝安区沙井街道后亭茅洲山工业园工业大厦全至科技创新园科创大厦2层2A
正则表达式是一组由字母和符号组成的特殊文本, 当你想要判断许多字符串是否符合某个特定格式;当你想在一大段文本中查找出所有的日期和时间;当你想要修改大量日志中所有的时间格式,在这些情况下,正则表达式都能帮上忙。
简单来说,正则表达式描述了一系列规则,通过这些规则,可以在字符串中找到相关的内容,规则使得搜索的能力更加强大。匹配的过程由正则表达式引擎完成。开发者通常不需要关心正则表达式引擎的实现细节,直接使用其提供的能力即可。
大家可以先想象你正在写一个应用, 然后你想设定一个用户命名的规则, 让用户名包含字符,数字,下划线和连字符,以及限制字符的个数,好让名字看起来没那么丑. 我们使用以下正则表达式来验证一个用户名:
以上的正则表达式可以接受 john_doe , john12_as . 但不匹配 Jo , 因为它包含了大写的字母而且太短了.
本文将以C++语言为例,介绍其中的正则表达式相关知识。
C++中正则表达式的API基本上都位于
部分代码为了简化书写,都已经默认做了以下操作:
为了使大家有一个直观的感受,文章的开头先通过一些入门示例给大家一个直观的感受。在这个基础之上,再详细讲解其中的细节。
使用正则表达式的大致流程如下:首先你有一段需要处理的文本。这可能是一个字符串对象,也可能是一个文本文件,或者是一大堆日志。接下来你会有特定的目标,例如:找出文本中所有的时间和日期。这个时候你就需要根据可能的格式写出具体的正则表达式,例如,日期的格式是:2020-01-01,那么你的正则表达式可能是这样:。(你现在不必纠结与这个正则表达式是什么意思,因为这是本文接下来要讲解的内容。)
有了正则表达式之后,你需要将你的文本和正则表达式交给正则表达式引擎 – 由C++语言(或者其他语言)提供。引擎会在文本中搜索到匹配的结果。这个结果的格式可能是包含了多个组,例如:你可能需要分离出年份和月份。有了引擎返回的结果之后,你就可以进一步处理了。
使用正则表达式的流程大体都是一致的,下面是最常见(其他形式大多为其变种)的三种使用方式。
匹配是判断给定的字符串是否符合某个正则表达式。例如:你想判断当前文本是否全部由数字构成。
下面是一段代码示例:
在这段代码中:
判断第一个字符串是否匹配,这里将返回false
判断第二个字符串是否匹配,这里将返回true这段代码输出如下:
还有一些时候,我们要判断的并非是文本的全体是否匹配。而是在一大段文本中搜索匹配的目标。
下面是一段代码示例,这段示例演示了在一个字符串中查找数字:
来保存匹配的结果。除了
,还有
也很常用。前者是以
的形式返回结果,后者是以
的形式返回结果。
函数搜索结果这段代码输出如下:
最后,使用正则表达式的还有一个常见功能是文本替换。很多的编辑器都有这样的功能。
例如,下图是我的Visual Studio编译器,在搜索替换文本的时候,可以使用正则表达式,这时搜索的能力就更加强大了。“Find:”部分可以通过正则表达式来描述待替换的字符串,“Replace:”部分填写替换的字符串。
下面是在C++中使用正则表达式完成字符串替换的代码示例:
完成替换
输出结果最终输出的字符串如下:
通过上面的三个示例我们看到,,
和
三个函数是正则表达式的核心,它们会运行正则表达式引擎完成匹配,查找和替换任务。
C++中内置了多种正则表达式文法,在创建正则表达式的时候可以通过参数来选择。
不同的文法在表达上有一些不同,如果你原先已经很熟悉或者
文法的正则表达式,你可以直接使用它们。对于其他人来说,我们直接使用默认的ECMAScript文法即可(
的正则表达式也是使用ECMAScript文法)。
C++ 中的 ECMAScript 正则表达式文法是 ECMA-262 文法,你可以点击链接查看详细内容。
在代码中写字符串有时候是比较麻烦的,因为很多字符需要通过反斜杠转义。当有多个反斜杠连在一起时,就很容易写错或者理解错了。
当通过字符串来写正则表达式时,这个问题就更严重了。因为正则表达式本身也有一些字符需要转义。例如,对于这样一个字符串 大部分人恐怕很难一眼看出其含义了。
在正则表达式很复杂的时候,推荐大家使用来表达。这种表达式是告诉编译器:这里的内容是纯字符串,因此不再需要增加反斜杠来转义特殊字符。
Raw string literal 的格式如下:
这其中:
也就是说,中的
是你需要的字符串本身。
下面是一个代码示例:
它将输出:
可以看到,这里的双引号和反斜杠不会被解释成转义字符,而是当成字符串内容本身,因此会原样输出。这样就减少了转义字符的复杂度,于是更容易理解了。
正则表达式本身定义了一些特殊的字符,这些字符有着特殊的含义。它们如下表所示。
这些字符并不少,刚开始接触可能记不住,但随着下文的讲解,相信你会逐渐熟悉它们。
字符类,顾名思义:是对字符的分类。
例如:1234567890这些都属于数字字符类。除此之外,还有其他的分类,它们如下表所示:
这里我们可以看到:
作为标识,因此这两个字符是正则表达式的中的特殊字符。如果是想使用这两个字符本身,需要对它们进行转义。
内部,通过
来描述字符类的名称。
中可以通过
表示否定,即:字符类的反面。接下来我们看一个代码示例:
这段代码稍微有些长,但还是比较好理解的。
该程序的输出如下:
请仔细看一下这个输出,并确认与你的认知是否一致。这里的有些字符类包含了换行符,因此在输出的结果中也是换行的。
上面的示例中,我们一次只匹配了一个字符。这样做效率是很低的。
在很多时候,我们当然是想一次性匹配出一个完整的字符串。例如:一个手机号码。这种情况下,其实是多个数字字符的重复。
下面就是在正则表达式中描述重复的方式。它们通常跟在字符类的后面,描述该字符出现多次。
知道重复的方法之后,正则表达式的查找能力就更强大了。看一下下面这个代码示例:
在这段代码中:
match_result
用来存储查找的结果。regex_search
在字符串中查找匹配字符。[[:alnum:]]{5}
是指:字符或者数字出现5次。\\w{5,}
是指:字母,数字或者下划线出现5次或更多次。R"(\W{3,5})"
是指:非字母,数字或者下划线出现3次到5次。[[:digit:]]*
是指:数字出现任意多次。.+
是指:任意字符出现至少1次。[[:lower:]]?
是指:小写字母出现0次或者1次。该程序输出如下: