正则表达式

oneNeko 于 2021-12-29 发布

RegEx是正则表达式(Regular Expression)的简称。它便于匹配、查找和管理文本。

基本匹配

.:允许匹配任何字符,包括特殊字符和空格。

字符集[abc]:如果一个词中的字符可以是各种字符,我们就将所有的可选字符写进中括号[]中。

否定字符集[^abc]

字母范围[a-z]

数字范围[0-9]

重复

星号*:在字符后面加上*,表示一个字符匹配0次或多次

加号+:在字符后面加上+,表示一个字符匹配1次或多次

问号?:在字符后面加上+,表示一个字符匹配0次或1次(即可选)

大括号 {}

分组

我们可以对一个表达式进行分组,并用这些分组来引用或执行一些规则。为了给表达式分组,我们需要将文本包裹在()中。

引用组 单词 ha 和 haa 分组如下。第一组用\1来避免重复书写。这里的1表示分组的顺序。请在表达式的末尾键入\2以引用第二组。

文本:
ha-ha,haa-haa

正则:
(ha)-\1,(haa)-\2

结果:
ha-ha,haa-haa

括号(?:): 非捕获分组 您可以对表达式进行分组,并确保它不被引用捕获。例如,下面有两个分组,但我们用\1引用的第一个组实际上是指向第二个组,因为第一个是未被捕获的分组。

文本:
ha-ha,haa-haa

正则:
(?:ha)-ha,(haa)-\1

结果:
ha-ha,haa-haa

竖线|:允许一个表达式包含多个不同的分支。所有分支用|分隔。和在字符层面上运作的字符集[abc]不同,分支在表达式层面上运作。

转义字符 \ 在书写正则表达式时,我们会用到 { } [ ] / \ + * . $^ | ? 这些特殊字符 。为了匹配这些特殊字符本身,我们需要通过\将它们转义。

插入符^:匹配字符串的开始

美元符号$:匹配字符串的结束

单词字符\w: 匹配字母、数字和下划线

非单词字符\W:匹配除字母、数字和下划线之外的字符

数字字符\d:仅用来匹配数字

非数字字符\D:匹配除数字之外的字符

空白符\s:仅匹配空白字符

非空白符\S:匹配除空白符之外的字符

零宽断言

如果我们希望正在写的词语出现在另一个词语之前或之后,我们需要使用零宽断言

正向先行断言: (?=)
例如,我们要匹配文本中的小时值。只匹配后面有 PM 的数值

文本:
Date: 4 Aug 3PM

正则:
\d+(?=PM)

结果:
3PM

负向先行断言:(?!)
例如,我们要在文本中匹配除小时值以外的数字。我们需要在表达式后面使用负向先行断言 (?!),并在括号内的 ! 后面添加 PM,从而只匹配没有 PM 的数值。

文本:
Date: 4 Aug 3PM

正则:
\d+(?!PM)

结果:
4

正向后行断言: (?<=)
例如,我们要匹配文本中的金额数。只匹配前面带有 $ 的数字

正文:
Product Code: 1064 Price: $5

正则:
(?<=\$)\d+

结果
$5

负向后行断言: (?<!)
例如,我们要在文本中匹配除价格外的数字。只匹配前面没有 $ 的数字

正文:
Product Code: 1064 Price: $5

正则:
(?<!\$)\d+

结果:
1064

标志

标志改变表达式的输出。这就是标志也称为 修饰符 的原因。标志决定表达式是否将文本视作单独的行处理,是否区分大小写,或者是否查找所有匹配项。

全局标志/g
多行标志/m
忽略大小写标志/i

贪婪匹配

正则表达式默认执行贪婪匹配。这意味着匹配内容会尽可能长

正文:
ber beer beeer beeeer

贪婪匹配:
.*r
结果:
ber beer beeer beeeer

懒惰匹配:
.*?r
结果
ber

C++标准库

参见正则表达式库

#include <iostream>
#include <iterator>
#include <string>
#include <regex>

int main()
{
    std::string s = "Some people, when confronted with a problem, think "
        "\"I know, I'll use regular expressions.\" "
        "Now they have two problems.";

    std::regex self_regex("REGULAR EXPRESSIONS",
        std::regex_constants::ECMAScript | std::regex_constants::icase);
    if (std::regex_search(s, self_regex)) {
        std::cout << "Text contains the phrase 'regular expressions'\n";
    }

    // 匹配单词
    std::regex word_regex("(\\w+)");
    auto words_begin =
        std::sregex_iterator(s.begin(), s.end(), word_regex);
    auto words_end = std::sregex_iterator();

    std::cout << "Found "
        << std::distance(words_begin, words_end)
        << " words\n";

    // 输出长度大于6的单词
    const int N = 6;
    std::cout << "Words longer than " << N << " characters:\n";
    for (std::sregex_iterator i = words_begin; i != words_end; ++i) {
        std::smatch match = *i;
        std::string match_str = match.str();
        if (match_str.size() > N) {
            std::cout << "  " << match_str << '\n';
        }
    }

    //替换
    std::regex long_word_regex("(\\w{7,})");
    std::string new_s = std::regex_replace(s, long_word_regex, "[$&]");
    std::cout << new_s << '\n';
}

参考

Regex Learn