我正在使用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
}
}
Run Code Online (Sandbox Code Playgroud)
如果这样可行,那就太好了.范围将限制在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
}
}
Run Code Online (Sandbox Code Playgroud)
但match_t是一个const引用,因此它不可分配. (tl; dr我也不知道底层类型是什么,一般我不想知道,因为我更喜欢一个更通用的解决方案,我可以在这个正则表达式的例子之外使用.甚至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
}
}
// ...
}
}
}
Run Code Online (Sandbox Code Playgroud)
我不喜欢由于大括号的深层嵌套.
也许break
在每个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);
}
Run Code Online (Sandbox Code Playgroud)
哪个更好,但仍然不是很好.使用宏,可以隐藏大部分噪声.喜欢:
#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
}
Run Code Online (Sandbox Code Playgroud)
大括号实际上是由宏隐含的,但通过重新设置它可以使读数更清晰.
我能想到的另一个选择是进入boost :: sub_match类并添加一个转换函数来将该类型转换为bool,其返回值将是该matched
成员的返回值.然后我可以在if表达式中声明一个match_t变量,它会自动转换为if的布尔值.我不确定我是否在那里并且它不是通用的.
在风格上,我建议好坏的(只有最后3个实际工作,所以我可能会限制他们的评论).
另外,有没有人有更好的建议?请说明为什么你认为他们更好.
通常建议避免嵌套if
- 它们使代码更难以阅读.如果有嵌套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
}
}
Run Code Online (Sandbox Code Playgroud)
BEGS循环:
const char *types[] = {"type1", "type2", "typeN", 0};
for(const char **cur = types; *cur; cur++){
found = what[*cur];
if (found.matched){
//initiate robot uprising
break;
}
}
Run Code Online (Sandbox Code Playgroud)
你所有的其他例子(IMO)都是一种糟糕的编码风格.我更喜欢保持循环和ifs短.如果它不适合20行代码,那么最好做一些非常复杂的事情(这不是你的情况).如果它没有做任何复杂的事情,它需要重组.