【问题标题】:c++11 regexp and GCCc++11 正则表达式和 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

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

【问题讨论】:

  • 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]*))?(?:\\#(.*))?$"

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


【解决方案1】:

这里有两个问题:

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 demoC++ 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] 更正确,但这不是这里的问题,这部分代码可以正常工作。
猜你喜欢
  • 2016-09-17
  • 1970-01-01
  • 2011-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-21
  • 2015-06-27
  • 1970-01-01
相关资源
最近更新 更多