文章

正则表达式

正则表达式

该文记录正则表达式定义、语法、示例。

正则表达式

1 定义

正则表达式(英语:Regular expression,常简写为 regexregexpRE),又称规律表达式、正则表示式、正则表示法、规则表达式、常规表示法,是计算机科学概念,用简单字符串来描述、匹配文中全部匹配指定格式的字符串,现在很多文本编辑器都支持用正则表达式搜索、取代匹配指定格式的字符串。

2 语法

一个正则表达式通常被称为一个模式pattern),为用来描述或者匹配一系列匹配某个句法规则的字符串。大部分正则表达式的形式都有如下的结构:

2.1 选择

  • 竖线|: 代表选择(即或集),具有最低优先级。

2.2 数量限定

某个字符后的数量限定符用来限定前面这个字符允许出现的个数。最常见的数量限定符包括+?*(不加数量限定则代表出现一次且仅出现一次):

  • 加号+: 代表前面的字符必须至少出现一次。(1次或多次)。
  • 问号?: 代表前面的字符最多只可以出现一次。(0次或1次)。
  • 星号*: 代表前面的字符可以不出现,也可以出现一次或者多次。(0次、1次或多次)。

2.3 匹配

  • 圆括号(): 可以用来定义操作符的范围和优先度。

2.4 优先权

优先权符号
最高\
()(?:)(?=)[]
*+?{n}{n,}{n,m}
^$、中介字符
次最低串接,即相邻字符连接在一起
最低\|

2.5 常见规则

字符描述
\将下一个字符标记为一个特殊字符(File Format Escape)、或一个原义字符(Identity Escape,有 ^$()*+?.[\{\| 共计12个)、或一个向后引用(backreferences)、或一个八进制转义符。例如,n 匹配字符n\n 匹配一个换行符。\\ 匹配 \\( 则匹配 (
^匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 \n\r 之后的位置。
$匹配输入字符串的结束位置。如果设置了 RegExp 对象的 Multiline 属性,$ 也匹配 \n\r 之前的位置。
*匹配前面的子表达式零次或多次。例如,zo* 能匹配 zzo 以及 zoo 。*等价于{0,}。
+匹配前面的子表达式一次或多次。例如, zo+ 能匹配 zo 以及 zoo ,但不能匹配 z+ 等价于 {1,}
?匹配前面的子表达式零次或一次。例如, do(es)? 可以匹配 does 中的 dodoes? 等价于 {0,1}
{n}n是一个非负整数。匹配确定的n次。例如, o{2} 不能匹配 Bob 中的 o ,但是能匹配 food 中的两个 o
{n,}n是一个非负整数。至少匹配n次。例如, o{2,} 不能匹配 Bob 中的 o ,但能匹配 foooood 中的所有o。 o{1,} 等价于 o+o{0,} 则等价于 o
{n,m}mn均为非负整数,其中n<=m。最少匹配n次且最多匹配m次。例如, o{1,3} 将匹配 fooooood 中的前三个o。 o{0,1} 等价于 o? 。请注意在逗号和两个数之间不能有空格。
.匹配除 \r \n 之外的任何单个字符。要匹配包括 \r \n 在内的任何字符,请使用像 (. | \r | \n) 的模式。
(pattern)匹配 pattern 并获取这一匹配的子字符串。该子字符串用于向后引用。所获取的匹配可以从产生的Matches集合得到,可带数量后缀。
(?:pattern)匹配 pattern 但不获取匹配的子字符串,不存储匹配的子字符串用于向后引用。这在使用或字符 ( | ) 来组合一个模式的各个部分是很有用。例如 industr(?:y | ies) 就是一个比 industry | industries 更简略的表达式。
(?=pattern)正向肯定预查(look ahead positive assert),在任何匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如, Windows(?=95 | 98 | NT | 2000) 能匹配 Windows2000 中的 Windows ,但不能匹配 Windows3.1 中的 Windows 。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
(?!pattern)正向否定预查(negative assert),在任何不匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如 Windows(?!95 | 98 | NT | 2000) 能匹配 Windows3.1 中的 Windows ,但不能匹配 Windows2000 中的 Windows 。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始
(?<=pattern)反向(look behind)肯定预查,与正向肯定预查类似,只是方向相反。例如, (?<=95 | 98 | NT | 2000)Windows 能匹配 2000Windows 中的 Windows ,但不能匹配 3.1Windows 中的 Windows
(?<!pattern)反向否定预查,与正向否定预查类似,只是方向相反。例如 (?<!95 | 98 | NT | 2000)Windows 能匹配 3.1Windows 中的 Windows ,但不能匹配 2000Windows 中的 Windows
[xyz]字符集合(character class)。匹配所包含的任意一个字符。例如, [abc] 可以匹配 plain 中的 a 。特殊字符仅有反斜线\保持特殊含义,用于转义字符。其它特殊字符如星号、加号、各种括号等均作为普通字符。脱字符^如果出现在首位则表示负值字符集合;如果出现在字符串中间就仅作为普通字符。连字符 - 如果出现在字符串中间表示字符范围描述;如果如果出现在首位(或末尾)则仅作为普通字符。右方括号应转义出现,也可以作为首位字符出现。
[^xyz]排除型字符集合(negated character classes)。匹配未列出的任意字符。例如, [^abc] 可以匹配 plain 中的 plin
[a-z]字符范围。匹配指定范围内的任意字符。例如, [a-z] 可以匹配 az 范围内的任意小写字母字符。
[^a-z]排除型的字符范围。匹配任何不在指定范围内的任意字符。例如, [^a-z] 可以匹配任何不在 az 范围内的任意字符。
\b匹配一个单词边界,也就是指单词和空格间的位置。例如, er\b 可以匹配 never 中的 er ,但不能匹配 verb 中的 er
\B匹配非单词边界。 er\B 能匹配 verb 中的 er ,但不能匹配 never 中的 er
\cx匹配由x指明的控制字符。x的值必须为A-Za-z之一。否则,将 c 视为一个原义的 c 字符。
\d匹配一个数字字符。等价于 [0-9]。注意 Unicode 正则表达式会匹配全角数字字符。
\D匹配一个非数字字符。等价于 [^0-9]
\f匹配一个换页符。等价于 \x0c\cL
\n匹配一个换行符。等价于 \x0a\cJ
\r匹配一个回车符。等价于 \x0d\cM
\s匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [\f\n\r\t\v]。注意Unicode正则表达式会匹配全角空格符。
\S匹配任何非空白字符。等价于[^\f\n\r\t\v]
\t匹配一个制表符。等价于 \x09\cI
\v匹配一个垂直制表符。等价于 \x0b\cK
\w匹配包括下划线的任何单词字符。等价于 [A-Za-z0-9_] 。注意Unicode正则表达式会匹配中文字符。
\W匹配任何非单词字符。等价于 [^A-Za-z0-9_]

3 示例

原始字符串字面值(raw string literal)是 C++11 引入的新特性,使用方式 R"()"

原始字符串是原生的、不加处理的字符串,所见即所得,引号、斜杠无需 \ 转义。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <string>
#include <regex>

int main()
{
	std::string fun1 = "virtual bool is_empty() const;";
	std::string fun2 = "Test operator=(const Test& test);";
    // 这是一个判断是否是函数的正则
	std::regex regRaw(R"((virtual\s+)?(\w+)(\s+)(\w+(?:=|==)?)?\((.*)\)(\s+const)?;)");

	// 结果的第一个字符串是整个字符串
	std::smatch results;
	bool ret = std::regex_match(fun1, results, regRaw);
	for (auto result : results)
	{
		if (result.matched != false)
		{
			std::cout << result << std::endl;
		}
	}

	ret = std::regex_match(fun2, results, regRaw);
	for (auto result : results)
	{
		if (result.matched != false)
		{
			std::cout << result << std::endl;
		}
	}
	
	return 0;
}

参考

[1] https://zh.wikipedia.org/wiki/正则表达式

[2] https://zh.cppreference.com/w/cpp/regex

本文由作者按照 CC BY 4.0 进行授权