如何匹配非转义引号字符串和非引号字符串?

How to match non-escaped quoted strings and also non-quoted strings?

我有一个包含单引号、双引号和转义引号的字符串:

Telling myself 'you are \'great\' ' and then saying "thank you" feels "a \"little\" nice"

我想要一个单一的正则表达式:

  1. 单引号字符串
  2. 双引号字符串
  3. 不在引号中的字符串

预期结果:以下组

  1. 告诉自己
  2. 你是\'great\'
  3. 然后说
  4. 谢谢
  5. 感觉
  6. 一个\"little\"不错

要求:不要 return 引号,并忽略转义引号

我目前有:

正则表达式 #1 到 return 单引号和双引号 (source):

((?<![\])['"])((?:.(?!(?<![\])))*.?)

结果:

正则表达式 #2 到 return 非引号字符串:

((?<![\])['"]|^).*?((?<![\])['"]|$)

结果:

问题:

  1. 我无法使正则表达式 #2 将非引号字符串放入一致的组中
  2. 我无法将正则表达式 #1 和 #2 合并到 return 一个正则表达式函数中的所有字符串

这样的事情怎么样:

(?<!\)'(.+?)(?<!\)'|(?<!\)"(.+?)(?<!\)"|(.+?)(?='|"|$)

Demo.

这背后的基本思想是,它首先尝试将字符串与引号匹配,这样之后剩下的就是没有被引号括起来的字符串。您将在捕获组中拥有所有匹配的字符串(不包括引号)。

简化版:

(?<!\)(['"])(.+?)(?<!\)|(.+?)(?='|"|$)

Demo.


如果您不想使用捕获组,您可以调整它以使用 Lookarounds,如下所示:

(?<=(?<!\)').+?(?=(?<!\)')|(?<=(?<!\)").+?(?=(?<!\)")|(?<=^|['"]).+?(?=(?<!\)['"]|$)

Demo.

简化版:

(?<=(?<!\)(['"])).+?(?=(?<!\))|(?<=^|['"]).+?(?=(?<!\)['"]|$)

Demo.

JS 版本

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

https://regex101.com/r/5xfs7q/1


PCRE - 专业级,超级版..

(?|(?|\s*((?:[^'"\]|(?:\[\S\s][^'"\]*))+)(?<!\s)\s*|\s+(*SKIP)(*FAIL))|(?<!\)(?|"([^"\]*(?:\[\S\s][^"\]*)*)"|'([^'\]*(?:\[\S\s][^'\]*)*)')|([\S\s]))

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

这是我见过的最干净、最好的。 Wsp trim 和正则表达式只包含一个捕获组。

已解释

 (?|                           # BReset
      (?|                           # BReset
           \s*                           # Wsp trim
           (                             # (1 start), Non-quoted data
                (?:
                     [^'"\] 
                  |  (?: \ [\S\s] [^'"\]* )
                )+
           )                             # (1 end)
           (?<! \s )
           \s*                           # Wsp trim
        |                              # or,
           \s+ (*SKIP) (*FAIL)           # Skip intervals with all whitespace 
      )
   |  
      (?<! \ )                     # Not an escape behind
      (?|                           # BReset
           " 
           (                             # (1 start), double quoted string data
                [^"\]* 
                (?: \ [\S\s] [^"\]* )*
           )                             # (1 end)
           "
        |                              # or,
           '
           (                             # (1 start), single quoted string data
                [^'\]* 
                (?: \ [\S\s] [^'\]* )*
           )                             # (1 end)
           '
      )
   |  
      ( [\S\s] )                    # (1), Pass through, single char
                                    # Un-balanced " or ' or \ at EOF
 )