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

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。

【讨论】:

以上是关于在正则表达式中转义(\')单引号,它在两个单引号之间采用字符串。的主要内容,如果未能解决你的问题,请参考以下文章

在 SQL Server 中转义单引号

如何在单引号字符串中转义单引号

如何在 Presto 中转义单引号?

在 Javascript 中转义单引号

如何在 Sybase 中转义单引号

如何在 JavaScript 中转义单引号 ( ' )? [复制]