使用`re.sub()`进行可变长度替换

时间:2018-03-24 19:11:56

标签: python regex

我想替换所有出现的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吗?

5 个答案:

答案 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)=,直到不再有=

demo

答案 4 :(得分:1)

该问题明确要求一个不使用函数的解决方案,但是为了完整性和正在寻找更清晰解决方案的人(其中不涉及许多正则表达式技巧),可以将函数用作在Replacing a RegEx with a string of characters with the same length中:

re.sub('={3,}', lambda x: '-' * len(x.group()), s)