我正在使用 boost 的正则表达式库,我发现确定是否找到命名匹配然后使用该信息有点烦人。要检测命名匹配,我想这样做:
typedef boost::match_result<string::const_iterator> matches_t;
typedef matches_t::const_reference match_t;
boost::regex re("(?:(?<type1>aaaa)|(?<type2>bbbb)" /*...*/ "|(?<typeN>abcdefg)");
string str(SOME_STRING);
matches_t what;
boost::match_flag_type flags = boost::match_default;
if(regex_search(str.cbegin(), str.cend(), what, re, flags))
{
if((match_t type1 = what["type1"]).matched)
{
// do stuff with type1
}
else if((match_t type2 = what["type2"]).matched)
{
// do stuff with type2
}
// ...
else if((match_t typeN = what["typeN"]).matched)
{
// do stuff with typeN
}
}
如果那会奏效,那就太好了。范围将被限制在 if 的主体中,内存可以被有效地使用并且看起来相当干净。遗憾的是,它不起作用,因为您无法在列表中定义变量。:(
这可能是一种可能性:
if(regex_search(str.cbegin(), str.cend(), what, re, flags))
{
match_t found = what["type1"];
if(found.matched)
{
// do stuff with type1
}
else if((found = what["type2"]).matched)
{
// do stuff with type2
}
// ...
else if((found = what["typeN"]).matched)
{
// do stuff with typeN
}
}
但是 match_t 是一个 const 引用,所以它是不可分配的。 (tl;博士另外我不知道底层类型是什么,通常我真的不想知道,因为我更喜欢一种更通用的解决方案,我可以在这个正则表达式示例之外使用它。甚至 std:: move() 被用于什么 [...] 它变得更加冗长,并且文档没有说它对 sub_match 使用移动语义。当然,由于本文第一句中给出的原因,所有这些都没有实际意义段落。)
另一种选择是这样做:
if(regex_search(str.cbegin(), str.cend(), what, re, flags))
{
match_t type1 = what["type1"];
if(type1.matched)
{
// do stuff with type1
}
else {
match_t type2 = what["type2"];
if(type2.matched)
{
// do stuff with type2
}
// ...
else {
match_t typeN = what["typeN"];
if((match_t typeN = what["typeN"]).matched)
{
// do stuff with typeN
}
}
// ...
}
}
}
由于大括号嵌套很深,我不喜欢。
可能会像这样在每个主体break
的末尾滥用带有 s 的循环结构:if
if(regex_search(str.cbegin(), str.cend(), what, re, flags))
{
do{
{
match_t type1 = what["type1"];
if(type1.matched)
{
// do stuff with type1
break;
}
}
{
match_t type2 = what["type2"];
if(type2.matched)
{
// do stuff with type2
break;
}
}
// ...
{
match_t typeN = what["typeN"];
if(typeN.matched)
{
// do stuff with typeN
break;
}
}
} while(0);
}
哪个更好,但仍然不是很好。使用宏,可以隐藏大部分噪音。像:
#define IF(declare, cond) do{{declare;if(cond){
#define ELSE_IF(declare, cond) break;}}{declare; if(cond){
#define ELSE break;}}{{
#define END_IF break;}}}while(0);
if(regex_search(str.cbegin(), str.cend(), what, re, flags))
{
IF(match_t type1 = what["type1"], type1.matched)
{
// do stuff with type1
}
ELSE_IF(match_t type2 = what["type2"], type2.matched)
{
// do stuff with type2
}
// ...
ELSE_IF(match_t typeN = what["typeN"], typeN.matched)
{
// do stuff with typeN
}
END_IF
}
大括号实际上是由宏隐含的,但通过重述它们可以使阅读更清晰。
我能想到的另一个选择是进入 boost::sub_match 类并添加一个转换函数将该类型转换为返回值将是matched
成员的布尔值。然后我可以在 if 表达式中声明一个 match_t 变量,它会被 if 自动转换为布尔值。我不确定我是否还在那里,它不是通用的。
从风格上讲,我提出的建议是好是坏(只有最后 3 个实际上有效,所以我可能会限制对它们的评论)。
另外,有没有人有更好的建议?请说明您认为它们更好的原因。