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"

gcc4.7.2によってコンパイルされたboost1.52で得たもの:

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

ブースト1.52clang3.2:

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

私のコードの何が問題になっていますか?

4

3 に答える 3

4

Fraserからのヒントのおかげで、考えられる解決策の1つは次のとおりです。

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

ブーストの詳細は今のところわかりませんが、影響はないと思います。への呼び出しの後にファンキーな結果が得られる理由もわかりませんが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内で逆参照されたものを一時的にコピーすると問題が解決するようです。forstd::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 に答える