在正则表达式中转义(\')单引号,它在两个单引号之间采用字符串。
Posted
技术标签:
【中文标题】在正则表达式中转义(\\\')单引号,它在两个单引号之间采用字符串。【英文标题】:escaping(\') single quotes in a regex which takes string between two single quotes.在正则表达式中转义(\')单引号,它在两个单引号之间采用字符串。 【发布时间】:2017-12-25 17:27:01 【问题描述】:我有以下字符串:
std::string s("server ('m1.labs.teradata.com') username ('use\\')r_*5') password('u\" er 5') dbname ('default')");
我使用了以下代码:
int main()
std::regex re(R"('[^'\\]*(?:\\[\s\S][^'\\]*)*')");
std::string s("server ('m1.labs.teradata.com') username ('use\\')r_*5') password('u\" er 5') dbname ('default')");
unsigned count = 0;
for(std::sregex_iterator i = std::sregex_iterator(s.begin(), s.end(), re);
i != std::sregex_iterator();
++i)
std::smatch m = *i;
cout << "the token is"<<" "<< m.str() << endl;
count++;
cout << "There were " << count << " tokens found." << endl;
return 0;
上述字符串的输出是:
the token is 'm1.labs.teradata.com'
the token is 'use\')r_*5'
the token is 'u" er 5'
the token is 'default'
There were 4 tokens found.
现在如果代码中上面提到的字符串s是
std::string s("server ('m1.labs.ter\'adata.com') username ('use\\')r_*5') password('u\" er 5') dbname ('default')");
输出变成:
the token is 'm1.labs.ter'
the token is ') username ('
the token is ')r_*5'
the token is 'u" er 5'
the token is 'default'
There were 5 tokens found.
现在两个字符串的输出不同: 预期的输出是“提取括号和单引号之间的所有内容,即
the token is 'm1.labs.teradata.com'
the token is 'use\')r_*5'
the token is 'u" er 5'
the token is 'default'
There were 4 tokens found
我在代码中提到的正则表达式能够正确提取但无法转义“单引号”。它能够转义 ",) 等,但不能转义单引号。 可以修改正则表达式以产生我需要的输出。提前致谢。
【问题讨论】:
见Rules for C++ string literals escape character。要定义文字反斜杠,您必须在非原始字符串文字内将其加倍。有字面量字符串,也有在代码中定义字面量字符串的字符串字面量。 第二个字符串看起来没有正确转义。('m1.labs.ter\'adata.com')
应该是 ('m1.labs.ter\\'adata.com')
吗?
@WiktorStribiżew 我理解了解释,有什么办法可以改变正则表达式来转义字符串中的单引号:假设字符串是 ('user/'5') 正则表达式应该给我' user'5'(输出应该在单引号之间
如果你有"'a'b' text"
,你的意思是你想得到'a'b'
?
@WiktorStribiżew 就像我想提取('****')之间的代码'****'应该在这里提取。现在假设我有这个字符串作为输入:用户名( 'user\'09') 使用正则表达式提取的字符串应为:'user'09'。所以基本上应该完成单引号的转义。如果我不清楚,请告诉我。提前致谢
【参考方案1】:
您使用的是我昨天通过评论分享的正确正则表达式。它匹配单引号字符串文字,其中可能已经转义了单引号。
std::regex re(R"('([^'\\]*(?:\\[\s\S][^'\\]*)*)')");
std::string s("server ('m1.labs.teradata.com') username ('u\\'se)r_*5') password('uer 5') dbname ('default')");
unsigned count = 0;
for(std::sregex_iterator i = std::sregex_iterator(s.begin(), s.end(), re);
i != std::sregex_iterator();
++i)
std::smatch m = *i;
cout << "the token is"<<" "<< m.str(1) << endl;
count++;
cout << "There were " << count << " tokens found." << endl;
这里是my C++ demo
请注意,文字字符串 ('u\'se)r_*5')
应该像这样使用常规字符串文字定义,其中支持转义序列,文字反斜杠应该使用 \\
定义:
"('u\\'se)r_*5')"
或使用原始字符串文字,其中反斜杠表示文字反斜杠:
R"(('u\'se)r_*5'))"
R"(...)"
构成原始字符串文字。
模式详情:
'
- 单引号
[^'\\]*
- 除单引号和反斜杠之外的 0+ 个字符
(?:\\[\s\S][^'\\]*)*
- 零个或多个序列:
\\[\s\S]
- 任何反斜杠转义字符
[^'\\]*
- 除了 '
和 \
之外的 0+ 个字符
'
- 单引号。
请注意,为避免将第一个单引号匹配为转义引号,您需要调整表达式,如 this snippet:
std::regex re(R"((?:^|[^\\])(?:\\2)*'([^'\\]*(?:\\[\s\S][^'\\]*)*)')");
std::string s("server ('m1.labs.teradata.com') username ('u\\'se)r_*5') password('uer 5') dbname ('default')");
unsigned count = 0;
for(std::sregex_iterator i = std::sregex_iterator(s.begin(), s.end(), re);
i != std::sregex_iterator();
++i)
std::smatch m = *i;
cout << "the token is"<<" "<< m.str(1) << endl;
count++;
cout << "There were " << count << " tokens found." << endl;
(?:^|[^\\])(?:\\2)*
前缀将匹配字符串的开头或除\
之外的任何字符,然后是 2 个\
的 0+ 个序列,因此首先不会抓取转义的'
。
最后,如果您只需要将匹配列表放入向量中,您可以使用
#include <iostream>
#include <string>
#include <vector>
#include <regex>
using namespace std;
int main()
std::regex rx("'[^']*(?:''[^']*)*'");
std::string sentence("server ('m1.labs.\\''tera\"da ta.com') username ('us *(er'')5') password('uer 5') dbname ('default')");
std::vector<std::string> names(std::sregex_token_iterator(sentence.begin(), sentence.end(), rx),
std::sregex_token_iterator());
for( auto & p : names ) cout << p << endl;
return 0;
请参阅C++ demo。
【讨论】:
以上是关于在正则表达式中转义(\')单引号,它在两个单引号之间采用字符串。的主要内容,如果未能解决你的问题,请参考以下文章