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

Posted

技术标签:

【中文标题】正则表达式在 g++ 4.9 下匹配,但在 g++-5.3.1 下失败【英文标题】:Regex matches under g++ 4.9 but fails under g++-5.3.1 【发布时间】:2016-05-10 19:41:15 【问题描述】:

我正在用正则表达式标记一个字符串;这在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
                firstinput.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
                firstinput.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;

【问题讨论】:

顺便说一句,原始字符串可能有助于避免额外的转义:R"((\S+)|("[^"]*")|(\([^\)]+\)))" @Jarod42 谢谢,现在应该修复了。显然,在复制/粘贴期间添加了一个额外的) 请发布您是如何调用此函数的——如果您使用右值作为第一个参数调用它,则在您使用迭代器时该字符串可能无效。幕后的实际内存分配很容易在编译器版本之间发生变化,导致在旧版本中看起来还不错的内存在新版本中看起来不太好。 regex101.com/#pcre、R"(("[^\"]*\")|(\([^\)])+\)|(\S+))" 可以正常工作,但R"((\S+)|("[^\"]*\")|(\([^\)])+\))" 不能...(\S+ 在末尾或开头)。 @xaxxon 已添加,感谢您的反馈。如果需要更多信息,请告诉我。 【参考方案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以来修复了一个bug。

【讨论】:

是的,这确实是问题所在!事实上,几天前我了解到正则表达式是“渴望”并修复了一个类似的错误,但忘记了这个。谢谢!【参考方案2】:

您发布的内容不足以让我确定(您更新它显示您正在使用左值调用它,所以这篇文章可能不相关,但除非人们希望我接受,否则我会留下它它下来),但如果你正在做我所做的,你忘记了迭代器在源字符串中并且该字符串不再有效。

您可以从input 中删除const,但是能够在其中放置右值非常方便,所以.....

这是我为避免这种情况所做的 - 我将 unique_ptr 返回到看起来像结果的东西,但我将实际的源字符串连同它一起隐藏起来,因此在我用完它之前 strsing 不会消失。这可能是 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,所以 [] 语法没有'效果也不错。

【讨论】:

以上是关于正则表达式在 g++ 4.9 下匹配,但在 g++-5.3.1 下失败的主要内容,如果未能解决你的问题,请参考以下文章

关于正则表达式 ^ ,$ ,/g 的作用

正则表达式(/[^0-9]/g,'')中的"/g"是啥意思 ?????

正则表达式中的平衡组

值两侧的测量单位的正则表达式 (200 g/g 200)

JS~~!!!! /[^\d]/g 是啥意思啊

正则 /D/g