如何写python re.sub pattern 忽略单引号或双引号?

how write python re.sub pattern Ignore single or double quotes?

mystr = """{abc} [abc] (abc) ['abc'] ["abc"]"""
pattern = r'\babc\b'
mystr = re.sub(pattern, "nnn", mystr)
print(mystr)
# {nnn} [nnn] (nnn) ['nnn'] ["nnn"]

但是,我希望 return {nnn} [nnn] (nnn) ['abc'] ["abc"]

如何忽略单引号或双引号?

您可以使用正则表达式模式,该模式仅在大括号、方括号或圆括号内精确定位 abc

mystr = """{abc} [abc] (abc) ['abc'] ["abc"]"""
output = re.sub(r'([{(\[])abc([})\]])', r'nnn', mystr)
print(output)  # {nnn} [nnn] (nnn) ['abc'] ["abc"]

对于仅针对元素 not 引用的更通用的解决方案,然后将 re.sub 与回调函数一起使用:

mystr = """{abc} [abc] (abc) ['abc'] ["abc"]"""
output = re.sub(r'([{(\[])(.*?)([})\]])', lambda m: m.group(1) + 'nnn' + m.group(3) if not re.search(r"^['\"].*['\"]$", m.group(2)) else m.group(), mystr)
print(output)  # {nnn} [nnn] (nnn) ['abc'] ["abc"]

如果您想要一个简单的解决方案来替换 abc 由引号以外的任何 non-word 字符界定,您可以将 pattern 更改为:

pattern = r'[^\w\'\"]abc[^w\'\"]'

您可以通过将单词边界与环视相结合来忽略单引号或双引号,以断言左侧不是单引号或双引号 (?<![\'"]) 并且右侧不是单引号或双引号 (?![\'"])

例子

mystr = """{abc} [abc] (abc) ['abc'] ["abc"]"""
output = re.sub(r'\b(?<![\'"])abc\b(?![\'"])', r'nnn', mystr)
print(output)

输出

{nnn} [nnn] (nnn) ['abc'] ["abc"]

如果你想用相同的引号配对相同的左括号和右括号,你可以使用带有交替、捕获组和反向引用的模式来首先匹配你不想替换的内容。

最后一个alternative有capture group 4,包含了你最终想要替换的东西,你可以在re.sub的回调中检查group 4。

import re

pattern = r"{([\"'])[^{}]*}|\[([\"'])[^][]*]|\(([\"'])[^()]*\)|((?<={)[^{}]*(?=})|(?<=\()[^()]*(?=\))|(?<=\[)[^][]*(?=]))"

s = ("{abc} [abc] (abc) ['abc'] [\"abc\"]\n"
            "{\"abc\"} ('abc')(\"abc\")\n"
            "{abc](\"abc\"}{'abc\"}")

result = re.sub(pattern, lambda m: 'nnn' if m.group(4) else m.group(), s)
print(result)

输出

{nnn} [nnn] (nnn) ['abc'] ["abc"]
{"abc"} ('abc')("abc")
{nnn}{nnn}

看到一个regex101 demo for all the matches and a Python demo.