正则表达式匹配g ++ 4.9但在g ++ - 5.3.1下失败

时间:2016-05-10 19:41:15

标签: c++ regex c++11 g++

我正在使用正则表达式对字符串进行标记;这通常在g++-4.9下有效,但在g++-5.3.1下失败。

我有以下txt文件:

0001-SCAND ==> "Scandaroon" (from Philjumba)
0002-KINVIN ==> "King's Vineyard" (from Philjumba)
0003-HANNI ==> "Hannibal: Rome vs. Carthage" (from Philjumba)
0004-LOX ==> "Lords of Xidit" (from Philjumba)

我使用正则表达式,空格,引号对和括号对进行标记。例如,第一行应该如下标记:

0001-SCAND
==>
"Scandaroon"
(from Philjumba)

我写了以下std::regex

std::regex FPAT("(\\S+)|(\"[^\"]*\")|(\\([^\\)]+\\))";

我用以下字符串对字符串进行标记:

std::vector<std::string>
split( const std::string & input, const std::regex & regex ) {

        std::sregex_token_iterator
                first{input.begin(), input.end(), regex, 0},
                last;

        return {first, last};
}

返回匹配项。在g++-4.9下,字符串会根据请求进行标记,但在g++-5.3.1下,它会被标记为如下所示:

0001-SCAND
==>
"Scandaroon"
(from
Philjumba)

或第三行标记如下:

0003-HANNI
==>
"Hannibal:
Rome
vs.
Carthage"
(from
Philjumba)

问题是什么?

编辑:我调用的函数如下:

std::string line("0001-SCAND ==> \"Scandaroon\" (from Philjumba)");
auto elems = split( line, FPAT );

编辑:根据@xaxxon的反馈,我替换了一个向量返回迭代器,但它在g++-5.3下仍无法正常工作。

std::vector<std::string>
split( const std::string & input, const std::regex & regex ) {

        std::sregex_token_iterator
                first{input.begin(), input.end(), regex, 0},
                last;

        std::vector< std::string > elems;
        elems.reserve( std::distance(first,last) );

        for ( auto it = first; it != last; ++ it ) {
                //std::cout << (*it) << std::endl;
                elems.push_back( *it );
        }

        return elems;
}

2 个答案:

答案 0 :(得分:1)

正则表达式 Eager

因此对于正则表达式"Set|SetValue"和文本"SetValue",正则表达式创建"Set"

您必须仔细选择订单:

std::regex FPAT(R"(("[^\"]*\")|(\([^\)])+\)|(\S+))");

\S+最后是最后一次考虑。

另一种方法是不使用默认选项(参见http://en.cppreference.com/w/cpp/regex/syntax_option_type) 并使用std::::regex::extended

std::regex FPAT(R"((\S+)|("[^\"]*\")|(\([^\)])+\))", std::::regex::extended);

因此,g ++ - 5.3.1似乎修复了一个错误,因为g ++ - 4.9就此而言。

答案 1 :(得分:0)

你没有足够的帖子让我知道(你更新它显示你用左值调用它,所以这篇文章可能不属于,但我会留下它除非人们要我把它拿下来,但是如果你正在做我做的事情,你就忘记了迭代器是在源字符串中而且该字符串不再有效。

您可以从const中移除input,但是能够将rvalue放在那里非常方便,所以......

这就是我要做的事情,以避免这种情况 - 我将unique_ptr返回到看起来像结果的东西,但我隐藏了实际的源字符串,以便在我和#之前strsing不会消失39;完成后使用它。这可能是UB,但我认为它几乎会一直有效:

// Holds a regex match as well as the original source string so the matches remain valid as long as the 
// caller holds on to this object - but it acts just like a std::smatch
struct MagicSmatch {
    std::smatch match;
    std::string data;

    // constructor makes a copy of the string and associates
    // the copy's lifetime with the iterators into the string (the smatch)
    MagicSmatch(const std::string & data) : data(data)
    {}
};

// this deleter knows about the hidden string and makes sure to delete it
// this cast is probably UB because std::smatch isn't a standard layout type
struct MagicSmatchDeleter {
    void operator()(std::smatch * smatch) {
        delete reinterpret_cast<MagicSmatch *>(smatch);
    }
};


// the caller just thinks they're getting a smatch ptr.. but we know the secret
std::unique_ptr<std::smatch, MagicSmatchDeleter> regexer(const std::regex & regex, const std::string & source)
{
    auto magic_smatch = new MagicSmatch(source);
    std::regex_search(magic_smatch->data, magic_smatch->match, regex);
    return std::unique_ptr<std::smatch, MagicSmatchDeleter>(reinterpret_cast<std::smatch *>(magic_smatch));

}

只要你将其称为auto results = regexer(....),那么它很容易使用,虽然results是指针,而不是正确的smatch,所以[]语法不能很好地工作。