编程代码
新闻详情

C++与正则表达式入门(一)

发布时间:2020-10-16 11:36:45 最后更新:2020-11-23 14:32:15 浏览次数:2121

什么是正则表达式?

正则表达式是一组由字母和符号组成的特殊文本, 当你想要判断许多字符串是否符合某个特定格式;当你想在一大段文本中查找出所有的日期和时间;当你想要修改大量日志中所有的时间格式,在这些情况下,正则表达式都能帮上忙。

简单来说,正则表达式描述了一系列规则,通过这些规则,可以在字符串中找到相关的内容,规则使得搜索的能力更加强大。匹配的过程由正则表达式引擎完成。开发者通常不需要关心正则表达式引擎的实现细节,直接使用其提供的能力即可。

大家可以先想象你正在写一个应用, 然后你想设定一个用户命名的规则, 让用户名包含字符,数字,下划线和连字符,以及限制字符的个数,好让名字看起来没那么丑. 我们使用以下正则表达式来验证一个用户名:

learn-regex

以上的正则表达式可以接受 john_doe , john12_as . 但不匹配 Jo , 因为它包含了大写的字母而且太短了.

本文将以C++语言为例,介绍其中的正则表达式相关知识。



C++中正则表达式的API基本上都位于头文件中。

部分代码为了简化书写,都已经默认做了以下操作:


入门示例

为了使大家有一个直观的感受,文章的开头先通过一些入门示例给大家一个直观的感受。在这个基础之上,再详细讲解其中的细节。

使用正则表达式的大致流程如下:首先你有一段需要处理的文本。这可能是一个字符串对象,也可能是一个文本文件,或者是一大堆日志。接下来你会有特定的目标,例如:找出文本中所有的时间和日期。这个时候你就需要根据可能的格式写出具体的正则表达式,例如,日期的格式是:2020-01-01,那么你的正则表达式可能是这样:。(你现在不必纠结与这个正则表达式是什么意思,因为这是本文接下来要讲解的内容。)

有了正则表达式之后,你需要将你的文本和正则表达式交给正则表达式引擎 – 由C++语言(或者其他语言)提供。引擎会在文本中搜索到匹配的结果。这个结果的格式可能是包含了多个组,例如:你可能需要分离出年份和月份。有了引擎返回的结果之后,你就可以进一步处理了。

img

使用正则表达式的流程大体都是一致的,下面是最常见(其他形式大多为其变种)的三种使用方式。

匹配

匹配是判断给定的字符串是否符合某个正则表达式。例如:你想判断当前文本是否全部由数字构成。

下面是一段代码示例:


在这段代码中:

  1. 这是一个包含了数字和字母的字符串
  2. 这是一个只包含了数字的字符串
  3. 这是我们的正则表达式,它表示:有多个数字cpp
  4. 通过判断第一个字符串是否匹配,这里将返回false
  5. 通过判断第二个字符串是否匹配,这里将返回true

这段代码输出如下:


搜索

还有一些时候,我们要判断的并非是文本的全体是否匹配。而是在一大段文本中搜索匹配的目标。

下面是一段代码示例,这段示例演示了在一个字符串中查找数字:

  1. 这是一个包含了数字和字母的字符串
  2. 和前面一样的正则表达式
  3. 通过来保存匹配的结果。除了,还有也很常用。前者是以的形式返回结果,后者是以的形式返回结果。
  4. 通过函数搜索结果
  5. 打印出匹配的结果

这段代码输出如下:

替换

最后,使用正则表达式的还有一个常见功能是文本替换。很多的编辑器都有这样的功能。

例如,下图是我的Visual Studio编译器,在搜索替换文本的时候,可以使用正则表达式,这时搜索的能力就更加强大了。“Find:”部分可以通过正则表达式来描述待替换的字符串,“Replace:”部分填写替换的字符串。

image-20200723135813276

下面是在C++中使用正则表达式完成字符串替换的代码示例:

  1. 仍然是前面这个字符串
  2. 仍然是同样的正则表达式
  3. 通过完成替换
  4. 通过输出结果

最终输出的字符串如下:

通过上面的三个示例我们看到,三个函数是正则表达式的核心,它们会运行正则表达式引擎完成匹配,查找和替换任务。

正则表达式文法

文法

C++中内置了多种正则表达式文法,在创建正则表达式的时候可以通过参数来选择。


不同的文法在表达上有一些不同,如果你原先已经很熟悉或者文法的正则表达式,你可以直接使用它们。对于其他人来说,我们直接使用默认的ECMAScript文法即可(的正则表达式也是使用ECMAScript文法)。

C++ 中的 ECMAScript 正则表达式文法是 ECMA-262 文法,你可以点击链接查看详细内容。

下文中,将会 引用 保罗的酒吧:关于正则表达式的解释

Raw string literal (原始字符串)

在代码中写字符串有时候是比较麻烦的,因为很多字符需要通过反斜杠转义。当有多个反斜杠连在一起时,就很容易写错或者理解错了。

当通过字符串来写正则表达式时,这个问题就更严重了。因为正则表达式本身也有一些字符需要转义。例如,对于这样一个字符串  大部分人恐怕很难一眼看出其含义了。

在正则表达式很复杂的时候,推荐大家使用来表达。这种表达式是告诉编译器:这里的内容是纯字符串,因此不再需要增加反斜杠来转义特殊字符。

Raw string literal 的格式如下:

这其中:

  • delimiter是可选的分隔符,通常不用写
  • raw_characters是具体的字符串

也就是说,中的是你需要的字符串本身。

下面是一个代码示例:

它将输出:

可以看到,这里的双引号和反斜杠不会被解释成转义字符,而是当成字符串内容本身,因此会原样输出。这样就减少了转义字符的复杂度,于是更容易理解了。

特殊字符

正则表达式本身定义了一些特殊的字符,这些字符有着特殊的含义。它们如下表所示。

这些字符并不少,刚开始接触可能记不住,但随着下文的讲解,相信你会逐渐熟悉它们。

字符类

字符类,顾名思义:是对字符的分类。

例如:1234567890这些都属于数字字符类。除此之外,还有其他的分类,它们如下表所示:

这里我们可以看到:

  • 字符类通过作为标识,因此这两个字符是正则表达式的中的特殊字符。如果是想使用这两个字符本身,需要对它们进行转义。
  • 内部,通过来描述字符类的名称。
  • 中可以通过表示否定,即:字符类的反面。
  • 字母,数字和空白字符由于这些字符类非常常用,因此它们有简写的方法。简写使得正则表达式更加简洁,但表达的含义是一样的。

接下来我们看一个代码示例:

这段代码稍微有些长,但还是比较好理解的。

该程序的输出如下:

请仔细看一下这个输出,并确认与你的认知是否一致。这里的有些字符类包含了换行符,因此在输出的结果中也是换行的。

重复

上面的示例中,我们一次只匹配了一个字符。这样做效率是很低的。

在很多时候,我们当然是想一次性匹配出一个完整的字符串。例如:一个手机号码。这种情况下,其实是多个数字字符的重复。

下面就是在正则表达式中描述重复的方式。它们通常跟在字符类的后面,描述该字符出现多次。

知道重复的方法之后,正则表达式的查找能力就更强大了。看一下下面这个代码示例:

在这段代码中:

  1. 这里定义了一个函数,它接受一个正则表达式和字符串。
  2. match_result用来存储查找的结果。
  3. 设置输出格式,为了让输出对齐。
  4. 通过regex_search在字符串中查找匹配字符。
  5. 输出匹配的结果。
  6. 待匹配的字符串。
  7. [[:alnum:]]{5}是指:字符或者数字出现5次。
  8. \\w{5,}是指:字母,数字或者下划线出现5次或更多次。
  9. R"(\W{3,5})"是指:非字母,数字或者下划线出现3次到5次。
  10. [[:digit:]]*是指:数字出现任意多次。
  11. .+是指:任意字符出现至少1次。
  12. [[:lower:]]?是指:小写字母出现0次或者1次。

该程序输出如下:

在线客服 双翌客服
客服电话
  • 0755-23712116
  • 13822267203