2

我想将一串整数对解析为数字。我使用这段代码:

#include <iostream>
#include <boost/regex.hpp>

int main()
{
    boost::regex reg( "(\\d+):(\\d+)" );

    std::string test = "1:2 3:4 5:6";

    boost::sregex_token_iterator end;
    for( boost::sregex_token_iterator i( test.begin(), test.end(), reg ); i != end; ++i ) {
        boost::smatch what;
        if( boost::regex_match( i->str(), what, reg ) )
            std::cout << "found: \"" << what[1].str() << "\":\"" << what[2].str() << "\"" << std::endl;
    }

    return 0;
}

预期输出:

found: "1":"2"
found: "3":"4"
found: "5":"6"

我用 gcc 4.7.2 编译的 boost 1.52 得到了什么:

found: "2":"2"
found: "4":"4"
found: "6":"6"

提升 1.52 铿锵 3.2:

found: "":"2"
found: "":"4"
found: "":"6"

我的代码有什么问题?

4

3 回答 3

4

感谢弗雷泽的提示,一种可能的解决方案是:

for( boost::sregex_token_iterator i( test.begin(), test.end(), reg ); i != end; ++i ) {
    boost::smatch what;
    const std::string &str = i->str(); 
    if( boost::regex_match( str, what, reg ) )
       std::cout << "found: \"" << what[1].str() << "\":\"" << what[2].str() << "\"" << std::endl;
}

所以问题来自 i->str() 调用 boost::sub_match 方法的事实:

basic_string<value_type> str()const;

它按值返回 std::string 。因此,传递给 regex_match 和 boost::smatch 对象的临时性 std::string 实际上会记住原始字符串中的位置,这实际上在 boost::regex_match 完成后被销毁。类似的问题可以这样重现:

std::string function();
boost::smatch what;
if( boost::regex_match( function(), what, reg ) ) ...

或者我相信这样的代码也很容易受到攻击:

boost::smatch what;
if( boost::regex_match( std::string( "abc" ), what, reg ) ) ...

我不确定如何在编译时防止这种情况,是否应该将其视为错误。std::regex_match 似乎具有相同的签名,那里存在这个问题吗?

于 2013-03-05T01:38:02.900 回答
3

我不知道 Boost 现在有什么细节,但我认为它不会影响这一点。我也不知道为什么在调用 之后你会得到时髦的结果regex_match,但这不是必需的;token_iterator已经完成了那场比赛,所以你只需要

std::cout << (*i)[1].str() << ':' << (*i)[2].str() << std::endl;

或者,如果您愿意:

std::cout << i->str(1) << ':' << i->str(2) << std::endl;

请注意,这是 C++11。它也应该适用于 Boost,但我还没有尝试过。

于 2013-03-04T23:50:45.487 回答
3

我不确定 Boost.Regex 的实现细节,但似乎将循环sregex_token_iterator内的取消引用复制for到临时std::string解决了这个问题:

std::string copied( i->str() );
boost::smatch what;
if( boost::regex_match( copied, what, reg ) ) {
    std::cout << "found: \"" << what[1].str() << "\":\"" << what[2].str() << "\"" << std::endl;
}

希望对 Boost.Regex 有更好了解的人可以给出更好的答案。

于 2013-03-05T00:24:02.750 回答