c++11 正则表达式和 GCC

Posted

技术标签:

【中文标题】c++11 正则表达式和 GCC【英文标题】:c++11 regexp and GCC 【发布时间】:2015-12-16 20:07:37 【问题描述】:

根据https://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html#status.iso.2011,C++11标准的正则表达式引擎应该在GCC中完成。现在,谁能解释一下为什么这个简单的例子

#include <iostream>
#include <string>
#include <regex>


using namespace std;


int main ()

    string string_array[] = "http://www.cplusplus.com/reference/regex/regex_match/",
                             "tcp://192.168.2.1:1234/hello/how/are/you",
                             "https://mail.google.com/mail/u/0/?tab=wm#inbox/15178022db56df29?projector=1";
    regex e("^(?:([A-Za-z]+):)?(\\/0,3)([0-9.\\-A-Za-z]+)(?::(\\d+))?(?:\\/([^?#]*))?(?:\\?([^#]*))?(?:#(.*))?$");

    for(int i=0; i<3; i++)
    
        smatch sm;
        regex_match (string_array[i],sm,e);

        for (unsigned i=0; i<sm.size(); ++i)
        
            cout << "[" << sm[i] << "] ";
        

        cout << endl;
    
    return 0;

这个输出的结果(注意例如第二行的端口号解析不正确,但似乎有很多错误)

[http://www.cplusplus.com/reference/regex/regex_match/] [http] [//] [www.cplusplus.com/reference/regex] [] [regex_match/] [] [] 
[tcp://192.168.2.1:1234/hello/how/are/you] [tcp] [//] [192.168.2.1:1234/hello/how/are/you] [] [] [] [] 
[https://mail.google.com/mail/u/0/?tab=wm#inbox/15178022db56df29?projector=1] [https] [//] [mail.google.com/mail/u/0/?tab=wm] [] [] [] [inbox/15178022db56df29?projector=1] 

而它的python对应物

import re

string_array = ["http://www.cplusplus.com/reference/regex/regex_match/",
                         "tcp://192.168.2.1:1234/hello/how/are/you",
                         "https://mail.google.com/mail/u/0/?tab=wm#inbox/15178022db56df29?projector=1"]
e = re.compile("^(?:([A-Za-z]+):)?(\\/0,3)([0-9.\\-A-Za-z]+)(?::(\\d+))?(?:\\/([^?#]*))?(?:\\?([^#]*))?(?:#(.*))?$");

for i in range(len(string_array)):
    m = e.match(string_array[i])
    print(m.groups())

正确打印了吗?

('http', '//', 'www.cplusplus.com', None, 'reference/regex/regex_match/', None, None)
('tcp', '//', '192.168.2.1', '1234', 'hello/how/are/you', None, None)
('https', '//', 'mail.google.com', None, 'mail/u/0/', 'tab=wm', 'inbox/15178022db56df29?projector=1')

我在 archlinux 上使用 gcc 5.3.0

编辑:

我把程序改成了这个,检查了正则表达式 syntax_option_type 标志

#include <iostream>
#include <string>
#include <regex>


using namespace std;


int main ()

    string string_array[] = "http://www.cplusplus.com/reference/regex/regex_match/",
                             "tcp://192.168.2.1:1234/hello/how/are/you",
                             "https://mail.google.com/mail/u/0/?tab=wm#inbox/15178022db56df29?projector=1";
    regex e("^(?:([A-Za-z]+):)?(\\/0,3)([0-9.\\-A-Za-z]+)(?::(\\d+))?(?:\\/([^?#]*))?(?:\\?([^#]*))?(?:#(.*))?$");

    for(int i=0; i<3; i++)
    
        smatch sm;
        cout << "match: " <<regex_match (string_array[i],sm,e) << endl;

        for (unsigned i=0; i<sm.size(); ++i)
        
            cout << "[" << sm[i].str() << "] ";
        
    

    cout << endl;

    switch(e.flags())
    
        case regex_constants::basic:
            cout << "POSIX syntax was used" << endl;
            break;
        case regex_constants::awk:
            cout << "POSIX awk syntax was used" << endl;
            break;
        case regex_constants::ECMAScript:
            cout << "ECMA syntax was used" << endl;
            break;
        case regex_constants::egrep:
            cout << "POSIX egrep syntax was used" << endl;
            break;
    

    return 0;

最后我居然得到了

match: 1
[http://www.cplusplus.com/reference/regex/regex_match/] [http] [//] [www.cplusplus.com/reference/regex] [] [regex_match/] [] [] match: 1
[tcp://192.168.2.1:1234/hello/how/are/you] [tcp] [//] [192.168.2.1:1234/hello/how/are/you] [] [] [] [] match: 1
[https://mail.google.com/mail/u/0/?tab=wm#inbox/15178022db56df29?projector=1] [https] [//] [mail.google.com/mail/u/0/?tab=wm] [] [] [] [inbox/15178022db56df29?projector=1] 
ECMA syntax was used

这似乎真的是一个编译器错误..

【问题讨论】:

gcc.gnu.org/bugs regex_match 需要一个完整的字符串匹配,re.match 只需要一个匹配在字符串的开头。 @stribizhev 好的,但是由于regex_match返回true,像re.match(返回一个匹配对象)有什么区别? 您还有其他问题,您的 c++ 正则表达式 [0-9.\-A-Za-z]+ 中的连字符已正确转义。 好吧,我认为 C++ 正则表达式在技术上没有任何问题。它可以通过某些类跨越行,但除此之外,您一次只使用一个字符串,所以应该没问题。如果组没有被填充,那是因为它们碰巧不匹配可选组,但整个正则表达式成功。 "^(?:([A-Za-z]+):)?(/0,3)([0-9.\\-A-Za-z]+)(?::(\\d+))?(?:/([^?#\\r\\n]*))?(?:\\?([^#\\r\\n]*))?(?:\\#(.*))?$" 【参考方案1】:

这里有两个问题:

Match object groups()match_results 的区别 不应转义字符类中的字符

Python 中的match object groups() 返回从 Group 1 开始的所有子匹配(捕获的子字符串):

返回一个元组,其中包含匹配的所有子组,从 1 到模式中有多少组。

match_results 开始枚举从第 0 组开始的所有组(整个匹配):

如果成功,则不是empty,而是包含一系列sub_match对象:第一个sub_match元素对应整个匹配,如果正则表达式包含要匹配的子表达式(即,括号分隔的组),它们对应的子匹配作为连续的sub_match元素存储在match_results对象中。

第 3 组中的 \ 没有转义连字符,它被忽略,因此在 .A 之间创建了一个范围(= 在正常的正则表达式世界中为 [.-A])。

您不能在 POSIX 正则表达式的字符类中使用转义符号,这被视为错误。将连字符放在末尾以避免需要转义它(如[0-9.A-Za-z-]+)。

所以,在 Python 中,使用

e = re.compile("^(?:([A-Za-z]+):)?(\\/0,3)([0-9.A-Za-z-]+)(?::(\\d+))?(?:\\/([^?#]*))?(?:\\?([^#]*))?(?:#(.*))?$");

在 C++ 中:

regex e("^(?:([A-Za-z]+):)?(\\/0,3)([0-9.A-Za-z-]+)(?::(\\d+))?(?:\\/([^?#]*))?(?:\\?([^#]*))?(?:#(.*))?$");
// ...
for(int i=0; i<3; i++)

    smatch sm;
    regex_match (string_array[i],sm,e);

    for (unsigned i=1; i<sm.size(); ++i) // Here, start with the second element
    
        cout << "[" << sm[i] << "] ";
    

    cout << endl;

比较Python demo 和C++ demo。

【讨论】:

为什么不能在 C++ 正则表达式的字符类中使用转义符号?无论如何,我知道 match_result 确实返回了整个匹配,这与 match.groups() 只返回子匹配不同。这不是我指出的差异之一,问题是最后一个你写了 在 POSIX 中,我更正了自己。虽然我还在寻找参考。我认为默认使用 ECMA 语法。 我也认为默认是ECMA语法,至少根据cplusplus.com/reference/regex,尽管我知道它不是官方信息来源 你可以在字符类中转义任何你想要的东西,但是如果它是一个控制代码或一个属性构造,你就不会得到文字。而 ECMA 只是 javasctipt 语法,什么都没有。 @sln: 不在 POSIX 括号表达式中。【参考方案2】:

正则表达式工作正常。

改变

cout << "[" << sm[i] << "] ";

cout << "[" << sm[i].str() << "] ";

你会看到正确的结果。

【讨论】:

不,我没有看到正确的结果,问题是 stribizhev 指出的问题 我在 vs2013 上测试了你的例子,并得到了你一开始得到的错误结果。然后我换行,看看你所在的正确字符串。但如果你有决心,没关系! 说实话,sm[i].str()sm[i] 更正确,但这不是这里的问题,这部分代码可以正常工作。

以上是关于c++11 正则表达式和 GCC的主要内容,如果未能解决你的问题,请参考以下文章

gcc 4.8 或更早版本对正则表达式有问题吗?

linux安装gcc报错,该怎么解 E: 未发现软件包 gcc-c+ E: 无法按照正则表达式 gcc-c+ 找到任何软件包

C: 带有 MinGW 的正则表达式库

C: 带有 MinGW 的正则表达式库

[C/C++11]_[初级]_[使用正则表达式库regex]

boost和c++11的正则表达式regex和线程thread对比