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/bugsregex_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 objectgroups()
与 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的主要内容,如果未能解决你的问题,请参考以下文章
linux安装gcc报错,该怎么解 E: 未发现软件包 gcc-c+ E: 无法按照正则表达式 gcc-c+ 找到任何软件包