快速入门
教程
工具和语言
示例
参考
书评
正则表达式工具
grep
PowerGREP
RegexBuddy
RegexMagic
通用应用程序
EditPad Lite
EditPad Pro
语言和库
Boost
Delphi
GNU (Linux)
Groovy
Java
JavaScript
.NET
PCRE (C/C++)
PCRE2 (C/C++)
Perl
PHP
POSIX
PowerShell
Python
R
Ruby
std::regex
Tcl
VBScript
Visual Basic 6
wxWidgets
XML 模式
Xojo
XQuery 和 XPath
XRegExp
数据库
MySQL
Oracle
PostgreSQL
本网站上的更多内容
简介
正则表达式快速入门
正则表达式教程
替换字符串教程
应用程序和语言
正则表达式示例
正则表达式参考
替换字符串参考
书评
可打印 PDF
关于本网站
RSS 源和博客
RegexBuddy—The best regex editor and tester for C++ developers!

使用 std::regex 的 C++ 正则表达式

C++11 标准中定义的 C++ 标准库在 <regex> 头文件中提供了对正则表达式的支持。在 C++11 之前,<regex> 是 C++ 标准库的 TR1 扩展的一部分。当本网站提及 std::regex 时,它指的是 Dinkumware 对 C++ 标准库的实现,该实现包含在 Visual C++ 2008 及更高版本中。在针对 Win64 时,C++Builder XE3 及更高版本也支持它。在 Visual C++ 2008 中,命名空间是 std::tr1::regex,而不是 std::regex。

如果您禁用了使用经典 Borland 编译器的选项,则 C++Builder 10 及更高版本在针对 Win32 时支持 Dinkumware 实现 std::regex。在 C++Builder XE3 及更高版本中使用经典 Borland 编译器时,您可以使用 boost::regex 而不是 std::regex。虽然 TR1 和 C++11 中定义的 std::regex 定义了与 boost::regex 几乎相同的操作和类,但实际正则表达式风格有一些重要的区别。最重要的是,Boost 中的 ECMAScript 正则表达式语法添加了许多从 Perl 借用的特性,这些特性不是 ECMAScript 标准的一部分,也没有在 Dinkumware 库中实现。

六种正则表达式风格

在 std::regex_constants 中定义了六种不同的正则表达式风格或语法

大多数 C++ 参考都将 C++11 实现的正则表达式视为在 ECMA-262v3 和 POSIX 标准中定义的正则表达式。但实际上,C++ 实现与这些标准的关联非常松散。语法非常接近。唯一显著的差异在于 std::regex 即使在 ECMAScript 模式下也支持 POSIX 类,并且它对于哪些字符必须转义(如大括号和闭合方括号)以及哪些字符不必转义(如字母)有点特别。

但此语法的实际行为存在重要差异。在 std::regex 中,插入符号和美元符号 始终匹配嵌入式换行符,而在 JavaScript 和 POSIX 中,这是一个选项。对非参与组的反向引用无法匹配,就像大多数正则表达式风格一样,而在 JavaScript 中,它们会找到一个零长度匹配。在 JavaScript 中,\d\w 仅限于 ASCII,而 \s 匹配所有 Unicode 空白。这很奇怪,但所有现代浏览器都遵循规范。在 std::regex 中,使用 char 字符串时,所有 简写 都仅限于 ASCII。在 Visual C++ 中,但不在 C++Builder 中,它们在使用 wchar_t 字符串时支持 Unicode。在 Visual C++ 中使用 wchar_t 时,POSIX 类 也匹配非 ASCII 字符,但并不始终包含人们期望的所有 Unicode 字符。

在实践中,你将主要使用 ECMAScript 语法。它是默认语法,提供的功能比其他语法多得多。每当本网站上的教程提到 std::regex 而没有提到任何语法时,所写内容适用于 ECMAScript 语法,也可能适用于任何其他语法。你实际上只会在想要从旧 POSIX 代码或 UNIX 脚本中重复使用现有正则表达式时才使用其他语法。

创建正则表达式对象

在使用正则表达式之前,您必须创建一个模板类 std::basic_regex 的对象。如果您的主题是 char 数组或 std::string 对象,您可以使用此模板类的 std::regex 实例轻松完成此操作。如果您的主题是 wchar_t 数组或 std::wstring 对象,请使用 std::wregex 实例。

将正则表达式作为字符串作为第一个参数传递给构造函数。如果您想使用 ECMAScript 之外的正则表达式风格,请将适当的常量作为第二个参数传递。您可以将此常量与 std::regex_constants::icase 进行“或”运算,以使正则表达式不区分大小写。您还可以使用 std::regex_constants::nosubs 对其进行“或”运算,以将所有捕获组转换为非捕获组,如果您只关心整体正则表达式匹配并且不想提取由任何捕获组匹配的文本,这将使您的正则表达式更有效。

查找正则表达式匹配

使用您的主题字符串作为第一个参数和正则表达式对象作为第二个参数调用 std::regex_search(),以检查您的正则表达式是否可以匹配字符串的任何部分。如果您想检查您的正则表达式是否可以匹配整个主题字符串,请使用相同的参数调用 std::regex_match()。由于 std::regex 缺少仅在字符串开头和结尾匹配的锚点,因此在使用正则表达式验证用户输入时必须调用 regex_match()。

regex_search() 和 regex_match() 都只返回 true 或 false。要获取 regex_search() 匹配的字符串部分,或在使用任一函数时获取捕获组匹配的字符串部分,您需要将模板类 std::match_results 的对象作为第二个参数传递。然后,正则表达式对象将成为第三个参数。使用以下四个模板实例化之一的默认构造函数创建此对象

当函数调用返回 true 时,您可以调用 match_results 对象的 str()、position() 和 length() 成员函数来获取匹配的文本,或获取匹配相对于主题字符串的起始位置及其长度。在没有参数或使用 0 作为参数的情况下调用这些成员函数以获取整体正则表达式匹配。调用它们并传递 1 或更大值以获取特定捕获组的匹配。size() 成员函数指示捕获组的数量加上整体匹配的数量。因此,您可以将值传递到 size()-1 到其他三个成员函数。

将所有内容放在一起,我们可以像这样获取第一个捕获组匹配的文本

std::string subject("Name: John Doe");
std::string result;
try {
  std::regex re("Name: (.*)");
  std::smatch match;
  if (std::regex_search(subject, match, re) && match.size() > 1) {
    result = match.str(1);
  } else {
    result = std::string("");
  }
} catch (std::regex_error& e) {
  // Syntax error in the regular expression
}

查找所有正则表达式匹配项

要查找字符串中的所有正则表达式匹配项,您需要使用迭代器。使用以下四个模板实例化之一构造模板类 std::regex_iterator 的对象

通过使用三个参数调用构造函数来构造一个对象:一个字符串迭代器,指示搜索的起始位置,一个字符串迭代器,指示搜索的结束位置,以及正则表达式对象。如果找到任何匹配项,该对象将在构造时保存第一个匹配项。使用默认构造函数构造另一个迭代器对象以获取序列结束迭代器。您可以将第一个对象与第二个对象进行比较,以确定是否存在任何进一步的匹配项。只要第一个对象不等于第二个对象,您就可以取消引用第一个对象以获取 match_results 对象。

std::string subject("This is a test");
try {
  std::regex re("\\w+");
  std::sregex_iterator next(subject.begin(), subject.end(), re);
  std::sregex_iterator end;
  while (next != end) {
    std::smatch match = *next;
    std::cout << match.str() << "\n";
    next++;
  }
} catch (std::regex_error& e) {
  // Syntax error in the regular expression
}

替换所有匹配项

要替换字符串中的所有匹配项,请使用 std::regex_replace(),并将您的主题字符串作为第一个参数,将正则表达式对象作为第二个参数,并将带有替换文本的字符串作为第三个参数。该函数返回一个应用了替换的新字符串。

替换字符串语法与 JavaScript 类似,但并不完全相同。无论您使用哪种正则表达式语法或语法,都使用相同的替换字符串语法。您可以使用 $&$0 插入整个正则表达式匹配项,并使用 $1$9 插入前九个捕获组匹配的文本。无法插入由组 10 或更高匹配的文本。$10 及更高始终替换为空,如果正则表达式中捕获组少于请求的数字,则 $9 及更低替换为空。 $`(美元反引号)是匹配项左边的字符串部分,$'(美元引号)是匹配项右边的字符串部分。

| 快速入门 | 教程 | 工具和语言 | 示例 | 参考 | 书籍评论 |

| grep | PowerGREP | RegexBuddy | RegexMagic |

| EditPad Lite | EditPad Pro |

| Boost | Delphi | GNU (Linux) | Groovy | Java | JavaScript | .NET | PCRE (C/C++) | PCRE2 (C/C++) | Perl | PHP | POSIX | PowerShell | Python | R | Ruby | std::regex | Tcl | VBScript | Visual Basic 6 | wxWidgets | XML Schema | Xojo | XQuery & XPath | XRegExp |

| MySQL | Oracle | PostgreSQL |