正则表达式:匹配不在引号之间的单词

Regular expression: match word not between quotes

我想要一个 Python 正则表达式来匹配不在单引号之间的给定单词。我尝试使用 (?! ...) 但没有成功。

在下面的屏幕截图中,我想匹配除第 4 行中的所有 foe

此外,文本是作为一个大字符串给出的。

这是 link regex101 示例文本如下:

var foe = 10;
foe = "";
dark_vador = 'bad guy'
foe = ' I\'m your father, foe ! '
bar = thingy + foe

this正则表达式如何:

>>> s = '''var foe = 10;
foe = "";
dark_vador = 'bad guy'
' I\m your father, foe ! '
bar = thingy + foe'''
>>>
>>> re.findall(r'(?!\'.*)foe(?!.*\')', s)
['foe', 'foe', 'foe']

这里的技巧是确保表达式不匹配任何带有前导和尾随 ' 的字符串,并记住在 re 表达式中考虑其间的字符,然后是 .*

你可以试试这个:-

((?!\'[\w\s]*)foe(?![\w\s]*\'))

((?!\'[\w\s]*[\']*[\w\s]*)foe(?![\w\s]*[\']*[\w\s]*\'))

下面的正则表达式解决方案在大多数情况下都有效,但如果不平衡的单引号出现在字符串文字之外,它可能会中断,例如在评论中。

在上下文中匹配字符串的常用正则表达式技巧是匹配您需要替换和匹配的内容以及捕获您需要保留的内容。

这是一个示例 Python 演示:

import re
rx = r"('[^'\]*(?:\.[^'\]*)*')|\b{0}\b"
s = r"""
    var foe = 10;
    foe = "";
    dark_vador = 'bad guy'
    foe = ' I\'m your father, foe ! '
    bar = thingy + foe"""
toReplace = "foe"
res = re.sub(rx.format(toReplace), lambda m: m.group(1) if m.group(1) else 'NEWORD', s)
print(res)

Python demo

正则表达式看起来像

('[^'\]*(?:\.[^'\]*)*')|\bfoe\b

参见regex demo

('[^'\]*(?:\.[^'\]*)*') 部分将单引号字符串文字捕获到第 1 组中,如果匹配,则将其放回结果中, \bfoe\b 匹配整个单词 foe任何其他字符串上下文 - 随后被另一个词替换。

注意:要同时匹配双引号字符串文字,请使用 r"('[^'\]*(?:\.[^'\]*)*'|\"[^\"\]*(?:\.[^\"\]*)*\")".

以下正则表达式的捕获组 1 将包含 'foe'.

的匹配项
r'^(?:[^'\n]|\')*(?:(?<!\)'(?:[^'\n]|\')*(?:(?<!\)')(?:[^'\n]|\')*)*\b(foe)\b'

Start your engine!

Python 的正则表达式引擎执行以下操作。

^           : assert beginning of string
(?:         : begin non-capture group
  [^'\n]    : match any char other than single quote and line terminator
  |         : or
  \'       : match '\' then a single quote
)           : end non-capture group   
*           : execute non-capture group 0+ times
(?:         : begin non-capture group
  (?<!\)   : next char is not preceded by '\' (negative lookbehind)
  '         : match single quote
  (?:       : begin non-capture group
    [^'\n]  : match any char other than single quote and line terminator
    |       : or
    \'     : match '\' then a single quote
  )         : end non-capture group   
  *         : execute non-capture group 0+ times
  (?:       : begin non-capture group
    (?<!\) : next char is not preceded by '\' (negative lookbehind)
    '       : match single quote
  )         : end non-capture group
  (?:       : begin non-capture group
    [^'\n]  : match any char other than single quote and line terminator
    |       : or
    \'     : match '\' then a single quote
  )         : end non-capture group   
  *         : execute non-capture group 0+ times
)           : end non-capture group
*           : execute non-capture group 0+ times
\b(foe)\b   : match 'foe' in capture group 1