捕获是由标记子表达式在正则表达式匹配过程中“捕获”的迭代器范围。如果标记子表达式匹配多次,则每个标记子表达式可能会产生多个捕获。本文档解释了 Boost.Regex 中捕获和标记子表达式的表示方式和访问方式。
每当 Perl 正则表达式包含一个括号组 ()
时,它都会输出一个额外的字段,称为标记子表达式,例如表达式
(\w+)\W+(\w+)
有两个标记子表达式(分别称为 $1 和 $2),此外,完整匹配称为 $&,第一个匹配之前的部分称为 $`,匹配之后的部分称为 $'。因此,如果在 "@abc def--"
中搜索上述表达式,则我们得到
子表达式 |
找到的文本 |
---|---|
$` |
"@" |
$& |
"abc def" |
$1 |
"abc" |
$2 |
"def" |
$' |
"--" |
在 Boost.Regex 中,所有这些都可以通过 match_results
类访问,该类在调用其中一个正则表达式匹配算法(regex_search
、regex_match
或 regex_iterator
)时会被填充。因此,给定
boost::match_results<IteratorType> m;
Perl 和 Boost.Regex 的等效项如下所示
Perl |
Boost.Regex |
---|---|
$` |
|
$& |
|
$n |
|
$' |
|
在 Boost.Regex 中,每个子表达式匹配都由一个 sub_match
对象表示,这基本上只是一对迭代器,表示子表达式匹配的起始和结束位置,但提供了一些附加运算符,以便 sub_match
类型的对象的行为非常类似于 std::basic_string
:例如,它们可以隐式转换为 basic_string
,可以与字符串进行比较,可以添加到字符串中,或者可以输出到输出流。
当找到正则表达式匹配时,不需要所有标记子表达式都参与匹配,例如表达式
(abc)|(def)
可以匹配 $1 或 $2,但不能同时匹配两者。在 Boost.Regex 中,您可以通过访问 sub_match::matched
数据成员来确定哪些子表达式匹配。
当标记子表达式重复时,子表达式会被多次“捕获”,但是通常只可以使用最终捕获,例如,如果
(?:(\w+)\W+)+
与
one fine day
匹配,则 $1 将包含字符串“day”,所有之前的捕获都将被遗忘。
但是,Boost.Regex 具有一个实验性功能,允许保留所有捕获信息 - 这可以通过 match_results::captures
成员函数或 sub_match::captures
成员函数访问。这些函数返回一个容器,该容器包含在正则表达式匹配过程中获得的所有捕获的序列。以下示例程序显示了如何使用此信息
#include <boost/regex.hpp> #include <iostream> void print_captures(const std::string& regx, const std::string& text) { boost::regex e(regx); boost::smatch what; std::cout << "Expression: \"" << regx << "\"\n"; std::cout << "Text: \"" << text << "\"\n"; if(boost::regex_match(text, what, e, boost::match_extra)) { unsigned i, j; std::cout << "** Match found **\n Sub-Expressions:\n"; for(i = 0; i < what.size(); ++i) std::cout << " $" << i << " = \"" << what[i] << "\"\n"; std::cout << " Captures:\n"; for(i = 0; i < what.size(); ++i) { std::cout << " $" << i << " = {"; for(j = 0; j < what.captures(i).size(); ++j) { if(j) std::cout << ", "; else std::cout << " "; std::cout << "\"" << what.captures(i)[j] << "\""; } std::cout << " }\n"; } } else { std::cout << "** No Match found **\n"; } } int main(int , char* []) { print_captures("(([[:lower:]]+)|([[:upper:]]+))+", "aBBcccDDDDDeeeeeeee"); print_captures("(.*)bar|(.*)bah", "abcbar"); print_captures("(.*)bar|(.*)bah", "abcbah"); print_captures("^(?:(\\w+)|(?>\\W+))*$", "now is the time for all good men to come to the aid of the party"); return 0; }
这将产生以下输出
Expression: "(([[:lower:]]+)|([[:upper:]]+))+" Text: "aBBcccDDDDDeeeeeeee" ** Match found ** Sub-Expressions: $0 = "aBBcccDDDDDeeeeeeee" $1 = "eeeeeeee" $2 = "eeeeeeee" $3 = "DDDDD" Captures: $0 = { "aBBcccDDDDDeeeeeeee" } $1 = { "a", "BB", "ccc", "DDDDD", "eeeeeeee" } $2 = { "a", "ccc", "eeeeeeee" } $3 = { "BB", "DDDDD" } Expression: "(.*)bar|(.*)bah" Text: "abcbar" ** Match found ** Sub-Expressions: $0 = "abcbar" $1 = "abc" $2 = "" Captures: $0 = { "abcbar" } $1 = { "abc" } $2 = { } Expression: "(.*)bar|(.*)bah" Text: "abcbah" ** Match found ** Sub-Expressions: $0 = "abcbah" $1 = "" $2 = "abc" Captures: $0 = { "abcbah" } $1 = { } $2 = { "abc" } Expression: "^(?:(\w+)|(?>\W+))*$" Text: "now is the time for all good men to come to the aid of the party" ** Match found ** Sub-Expressions: $0 = "now is the time for all good men to come to the aid of the party" $1 = "party" Captures: $0 = { "now is the time for all good men to come to the aid of the party" } $1 = { "now", "is", "the", "time", "for", "all", "good", "men", "to", "come", "to", "the", "aid", "of", "the", "party" }
不幸的是,启用此功能会影响性能(即使您不使用它),如果您使用它,则影响更大,因此要使用此功能,您需要