正则表达式应该只匹配两种类型的带引号的字符串之一

Posted

技术标签:

【中文标题】正则表达式应该只匹配两种类型的带引号的字符串之一【英文标题】:regex should match only one of two types of quoted strings 【发布时间】:2019-07-17 19:57:04 【问题描述】:

我需要一个匹配用双引号括起来的字符串的正则表达式。如果此模式用单引号括起来,则它不应匹配用双引号括起来的字符串:

"string"
" 'xyz' "
"  `"    "
"  `" `"   "
"  `" `" `"  "
'  ' "should match" '  '
'   "should not match"   '

现在我有 (https://regex101.com/r/z5PayV/1)

(?:"(([^"]*`")*[^"]*|[^"]*)") 

匹配所有行。但是最后一行不应该匹配。有什么解决办法吗?

【问题讨论】:

就这一点而言,最后两行难道不适合同样的情况:一个用双引号括起来的字符串,也用单引号括起来?为什么倒数第二个匹配,而不是最后一个匹配? this pattern 是什么意思?您当前的整个正则表达式? @dvo 最后两行不适合相同的情况。如果想到像 bash 或 powershell 这样的 shell 脚本,最后一行代表一个字符串,而最后一行的秒数代表 3 个字符串。答案表明正则表达式能够解决这个问题。 【参考方案1】:

你必须跳过单引号才能将它们从匹配中排除

更新

对于 C#,必须这样做。 只需使用简单的 CaptureCollection 即可获取所有 引用的匹配项。

(?:'[^']*'|(?:"(([^"]*`")*[^"]*|[^"]*)")|[\S\s])+

展开

 (?:
      ' [^']* '

   |  
      (?:
           "
           (                             # (1 start)
                ( [^"]* `" )*                 # (2)
                [^"]* 
             |  [^"]* 
           )                             # (1 end)
           "
      )
   |  
      [\S\s] 
 )+

C#代码

var str =
"The two sentences are 'He said \"Hello there\"' and \"She said 'goodbye' and 'another sentence'\"\n" +
"\"  `\"    \"\n" +
"\"  `\"    \"\n" +
"\"  `\" `\"   \"\n" +
"\"  `\" `\" `\"  \"\n" +
"'   \"   \"   '\n" +
"\"string\"\n" +
"\" 'xyz' \"\n" +
"\"  `\"    \"\n" +
"\"  `\" `\"   \"\n" +
"\"  `\" `\" `\"  \"\n" +
"'  ' \"should match\" '  '\n" +
"'   \"should not match\"   '\n";

var rx = new Regex( "(?:'[^']*'|(?:\"(([^\"]*`\")*[^\"]*|[^\"]*)\")|[\\S\\s])+" );

Match M = rx.Match( str );
if (M.Success)

    CaptureCollection cc = M.Groups[1].Captures;
    for (int i = 0; i < cc.Count; i++)
        Console.WriteLine("0", cc[i].Value);

输出

She said 'goodbye' and 'another sentence'
  `"
  `"
  `" `"
  `" `" `"
string
 'xyz'
  `"
  `" `"
  `" `" `"
should match

不好意思,这是PCRE引擎的做法

'[^']*'(*SKIP)(*FAIL)|(?:"(([^"]*`")*[^"]*|[^"]*)")`

https://regex101.com/r/gMiVDU/1

   ' [^']* '
   (*SKIP) (*FAIL) 
|  
   (?:
        "
        (                             # (1 start)
             ( [^"]* `" )*                 # (2)
             [^"]* 
          |  [^"]* 
        )                             # (1 end)
        "
   )

___________________________-

【讨论】:

我接受了这个答案,尽管我认为第二个非捕获组是错误的。如果我删除它,双引号也会匹配。 @sln 你能确认一下吗?谢谢。 @TobiasWollgam - 你能具体说明哪个正则表达式以及你认为哪里有问题吗?谢谢。 @@TobiasWollgam - 请注意,在 C# 正则表达式中,整个字符串始终在单个匹配项中匹配。这是设计使然,它不会伤害任何东西,也不会减慢它的速度。所有组 1 捕获都记录在一个列表中。这就像类固醇上的 findall() 类型函数。 对不起,如果我不清楚。在您的输出中,我错过了前导和尾随双引号。所以我的解决方案是删除第二个非捕获组?:,使正则表达式变为(?:'[^']*'|("(([^"]*´")*[^"]*|[^"]*)")|[\S\s])+(将原来的反引号替换为前引号,因为反引号用于cmets中的代码标记)。现在您的 c# 代码的输出包含双引号。由于我没有使用我的生产代码对其进行测试,其中一个为来自第三方的 c# 匹配代码提供一个正则表达式对象,我不知道其中一个正则表达式是否有效。 @TobiasWollgam - 我明白了。当然,如果您想查看引号,您也可以在引号周围使用捕获组。事实上,所有组都维护一个单独的捕获集合(列表),您可以在匹配后迭代。示例:CaptureCollection cc1 = M.Groups[1].Captures; CaptureCollection cc2 = M.Groups[2].Captures; CaptureCollection cc3 = M.Groups[3].Captures; 等...【参考方案2】:

答案看起来很复杂,这是怎么回事:

^"(\d+|\D+)"$

是不是太简单了?

这里的想法是检查字符串是否以双引号 (") 开头和结尾,双引号内的任何内容(包括单引号)都是允许的。

【讨论】:

请详细说明 欢迎来到 Stack Overflow!您是否根据提供的示例检查了您的解决方案?

以上是关于正则表达式应该只匹配两种类型的带引号的字符串之一的主要内容,如果未能解决你的问题,请参考以下文章

正则表达式逐行:如何匹配三引号而不是双引号

正则基础之 环视

正则表达式删去双引号vscode

正则表达式

shell编程之grep命令

js之数据类型(对象类型——引用类型——正则)