【问题标题】:Regex replace (in Python) - a simpler way?正则表达式替换(在 Python 中) - 一种更简单的方法?
【发布时间】:2010-10-04 04:27:33
【问题描述】:

任何时候我想替换一段文本,它是一段较大文本的一部分,我总是需要这样做:

"(?P<start>some_pattern)(?P<replace>foo)(?P<end>end)"

然后将start 组与replace 的新数据连接起来,然后将end 组连接起来。

有没有更好的方法?

【问题讨论】:

  • 如果可以,请尝试在这种情况下预先标记数据(根据正则表达式规则将其分成更小的部分)并根据这些替换,因为这更有可能更容易完成类型的事情您正在做而不是在每次进行替换时处理整个文本文档,例如,如果您可以将 标记为单独的事物以开始(进入数组),这将使我更容易想一想,在短期内需要一点时间来适应,但从长远来看,它会让这些类型的事情变得更容易

标签: python regex


【解决方案1】:
>>> import re
>>> s = "start foo end"
>>> s = re.sub("foo", "replaced", s)
>>> s
'start replaced end'
>>> s = re.sub("(?<= )(.+)(?= )", lambda m: "can use a callable for the %s text too" % m.group(1), s)
>>> s
'start can use a callable for the replaced text too end'
>>> help(re.sub)
Help on function sub in module re:

sub(pattern, repl, string, count=0)
    Return the string obtained by replacing the leftmost
    non-overlapping occurrences of the pattern in string by the
    replacement repl.  repl can be either a string or a callable;
    if a callable, it's passed the match object and must return
    a replacement string to be used.

【讨论】:

  • 嗨罗杰,我一直在玩那个正则表达式字符串。我了解它的 RE 部分是如何工作的,但我不明白 python 如何将“开始”放在开头,将“结束”放在结尾。你觉得你能帮忙解释一下吗?谢谢! :)
  • 那些不被正则表达式“匹配”。 (查看m.group(0)。)它被分解为“开始(此处匹配的文本)结束”,匹配是被替换的内容。现在看(差不多一年后),我不知道我为什么要这样做,除了显示基本的后向和前瞻语法。
  • 请注意,这并没有利用已编译的正则表达式,因此每次使用正则表达式时都会产生额外的编译费用。
  • 这正是我想要的。谢谢
【解决方案2】:

在 Python re documentation 中查找前瞻 (?=...) 和后瞻 (?&lt;=...) -- 我很确定它们就是您想要的。它们匹配字符串,但不“消耗”它们匹配的字符串位。

【讨论】:

  • 问题在于它必须是固定宽度的。我需要一些允许更复杂模式的东西。
  • @Evan:在大多数正则表达式引擎中,它必须是固定宽度,仅用于后视。
  • Tomalak,我需要的是能够有一个非固定宽度的前缀模式。
【解决方案3】:

简短的版本是您不能在使用 Python 的 re 模块的后视中使用可变宽度模式。没有办法改变这一点:

>>> import re
>>> re.sub("(?<=foo)bar(?=baz)", "quux", "foobarbaz")
'fooquuxbaz'
>>> re.sub("(?<=fo+)bar(?=baz)", "quux", "foobarbaz")

Traceback (most recent call last):
  File "<pyshell#2>", line 1, in <module>
    re.sub("(?<=fo+)bar(?=baz)", "quux", string)
  File "C:\Development\Python25\lib\re.py", line 150, in sub
    return _compile(pattern, 0).sub(repl, string, count)
  File "C:\Development\Python25\lib\re.py", line 241, in _compile
    raise error, v # invalid expression
error: look-behind requires fixed-width pattern

这意味着您需要解决它,最简单的解决方案与您现在正在做的非常相似:

>>> re.sub("(fo+)bar(?=baz)", "\\1quux", "foobarbaz")
'fooquuxbaz'
>>>
>>> # If you need to turn this into a callable function:
>>> def replace(start, replace, end, replacement, search):
        return re.sub("(" + re.escape(start) + ")" + re.escape(replace) + "(?=" + re.escape + ")", "\\1" + re.escape(replacement), search)

这没有lookbehind 解决方案的优雅,但它仍然是一个非常清晰、直接的单行。如果你看一下 an expert has to say on the matter 的内容(他说的是 JavaScript,它完全缺乏后视功能,但许多原理都是相同的),你会发现他最简单的解决方案看起来很像这个。

【讨论】:

    【解决方案4】:

    我相信最好的办法是在一个组中捕获您想要替换的任何内容,然后使用捕获的组的 start 和 end 属性替换它。

    问候

    阿德里安

    #the pattern will contain the expression we want to replace as the first group
    pat = "word1\s(.*)\sword2"   
    test = "word1 will never be a word2"
    repl = "replace"
    
    import re
    m = re.search(pat,test)
    
    if m and m.groups() > 0:
        line = test[:m.start(1)] + repl + test[m.end(1):]
        print line
    else:
        print "the pattern didn't capture any text"
    

    这将打印: 'word1 永远不会是 word2'

    要替换的组可以位于字符串的任意位置。

    【讨论】:

    • 只有一个(后期)提示:去掉“0:”和“:len(test)”。它们是不必要的噪音。
    • @jae 还是需要冒号,不然不会拼接字符串。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-13
    • 1970-01-01
    • 2011-11-09
    • 1970-01-01
    相关资源
    最近更新 更多