我想替换所有出现的3个或更多" ="等号" - "。
def f(a, b):
'''
Example
=======
>>> from x import y
'''
return a == b
变为
def f(a, b):
'''
Example
-------
>>> from x import y
'''
return a == b # don't touch
我的工作但是hacky解决方案是将lambda传递给repl
re.sub()
,它抓住每场比赛的长度:
>>> import re
>>> s = """
... def f(a, b):
... '''
... Example
... =======
... >>> from x import y
... '''
... return a == b"""
>>> eq = r'(={3,})'
>>> print(re.sub(eq, lambda x: '-' * (x.end() - x.start()), s))
def f(a, b):
'''
Example
-------
>>> from x import y
'''
return a == b
我是否可以在不需要将函数传递给re.sub()
的情况下执行此操作?
我的想法是,我需要r'(=){3,}'
(一个可变长度的捕获组),但我相信re.sub(r'(=){3,}', '-', s)
有贪婪的问题。
我可以修改上面的正则表达式eq
,以便不需要lambda吗?
答案 0 :(得分:3)
在lookahead / lookbehind的帮助下,可以用char替换:
>>> re.sub("(=(?===)|(?<===)=|(?<==)=(?==))", "-", "=== == ======= asdlkfj")
... '--- == ------- asdlkfj'
答案 1 :(得分:2)
使用re.sub
,这会使用一些具有欺骗性的前瞻性技巧,并且假设您的替换模式后面始终跟有换行符'\n'
。
print(re.sub('=(?=={2}|=?\n)', '-', s))
def f(a, b):
'''
Example
-------
>>> from x import y
'''
return a == b
<强>详情
“如果有两个等号或可选的等号和换行符,则替换等号。”
= # equal sign if
(?=={2} # lookahead
| # regex OR
=? # optional equal sign
\n # newline
)
答案 2 :(得分:2)
这是可能的,但不可取。
re.sub
的工作方式是找到完整的匹配,然后替换它。它不会单独替换每个捕获组,因此re.sub(r'(=){3,}', '-', s)
之类的东西不会起作用 - 它会用短划线取代整个匹配,而不是每次出现=
字符。
>>> re.sub(r'(=){3,}', '-', '=== ===')
'- -'
因此,如果你想避免使用lambda,你必须编写一个匹配单个=
个字符的正则表达式 - 但前提是它们中至少有3个。当然,这比简单地将3个或更多=
个字符与简单模式={3,}
匹配要困难得多。它需要使用一些外观,看起来像这样:
(?<===)=|(?<==)=(?==)|=(?===)
这样做你想要的:
>>> re.sub(r'(?<===)=|(?<==)=(?==)|=(?===)', '-', '= == === ======')
'= == --- ------'
但它的可读性明显低于原始lambda
解决方案。
答案 3 :(得分:2)
使用regex module,您可以写:
regex.sub(r'\G(?!\A)=|=(?===)', '-', s)
\G
是紧接在最后一次成功匹配或字符串开头之后的位置。(?!\A)
强制字符串的开头失败。当=(?===)
后跟另外两个=
时,第二个分支=
会成功。然后,下一个匹配使用第一个分支\G(?!\A)=
,直到不再有=
。
答案 4 :(得分:1)
该问题明确要求一个不使用函数的解决方案,但是为了完整性和正在寻找更清晰解决方案的人(其中不涉及许多正则表达式技巧),可以将函数用作在Replacing a RegEx with a string of characters with the same length中:
re.sub('={3,}', lambda x: '-' * len(x.group()), s)