代码之家  ›  专栏  ›  技术社区  ›  Brad Solomon

可变长度替换为“re”。sub()`

  •  7
  • Brad Solomon  · 技术社区  · 8 年前

    我想用相等数量的“-”替换所有出现的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
    

    我的可行但棘手的解决方案是将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
    

    我可以在不需要向传递函数的情况下执行此操作吗 回复:。sub() ?

    我的想法是我需要 r'(=){3,}' (可变长度捕获组),但 re.sub(r'(=){3,}', '-', s) 我相信他有贪心的问题。

    我可以修改regex吗 eq 这样就不需要lambda了?

    5 回复  |  直到 8 年前
        1
  •  3
  •   Marat    8 年前

    在lookahead/lookbehind的帮助下,可以用char替换:

    >>> re.sub("(=(?===)|(?<===)=|(?<==)=(?==))", "-", "=== == ======= asdlkfj")
    ... '--- == ------- asdlkfj'
    
        2
  •  2
  •   cs95 abhishek58g    8 年前

    使用 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
    )
    
        3
  •  2
  •   Aran-Fey Kevin    8 年前

    这是可能的,但不可取。

    这条路 re.sub 工作就是找到一个 完成 匹配,然后替换它。它不会单独替换每个捕获组 re.sub(r'(=){3,}', '-', s) 不起作用-这将用破折号替换整个匹配,而不是每次出现 = 性格

    >>> re.sub(r'(=){3,}', '-', '=== ===')
    '- -'
    

    所以,如果要避免lambda,就必须编写一个与单个 = 字符-但前提是至少有3个字符。当然,这比简单地匹配3个或更多个要困难得多 = 具有简单图案的字符 ={3,} 。它需要使用一些lookarounds,如下所示:

    (?<===)=|(?<==)=(?==)|=(?===)
    

    这就是您想要的:

    >>> re.sub(r'(?<===)=|(?<==)=(?==)|=(?===)', '-', '= == === ======')
    '= == --- ------'
    

    但很明显,它的可读性远不如原文 lambda 解决方案

        4
  •  2
  •   Casimir et Hippolyte    8 年前

    使用 regex module ,您可以编写:

    regex.sub(r'\G(?!\A)=|=(?===)', '-', s)
    
    • \G 是上一次成功匹配或字符串开头之后的位置。
    • (?!\A) 强制字符串的开头失败。

    第二分支机构 =(?===) = 后面跟着另外两个 = 。然后接下来的匹配使用第一个分支 \G(?!\A)= 直到没有连续的 =

    demo

        5
  •  2
  •   cookiemonster    6 年前

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

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