在正则表达式中转义(\')单引号,它在两个单引号之间取字符串。

时间:2017-07-20 07:02:22

标签: c++ regex token

我有以下字符串:

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.

现在,如果代码中上面提到的字符串是

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

我在代码中提到的正则表达式能够正确提取但不能逃脱“单引号”。它能够逃脱“,”等但不是单引号。 可以修改正则表达式以产生我需要的输出。提前谢谢。

1 个答案:

答案 0 :(得分:0)

您正在使用我昨天通过评论分享的正确正则表达式。它匹配单引号的字符串文字,这些文字可能已经转义了单引号。

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