在单个lin中替换所有regex匹配项

2024-06-13 03:41:04 发布

您现在位置:Python中文网/ 问答频道 /正文

我有动态regexp,我不知道它有多少组 我想用xml标记替换所有匹配项

示例

re.sub("(this).*(string)","this is my string",'<markup>\anygroup</markup>')
>> "<markup>this</markup> is my <markup>string</markup>"

这在一条线上有可能吗?


Tags: 标记re示例stringismy动态xml
3条回答

re.sub()将尽其所能取代一切。如果您为它传递一个repl函数,那么您可以做更多的事情。

是的,这可以在一行中完成。

>>> re.sub(r"\b(this|string)\b", r"<markup>\1</markup>", "this is my string")
'<markup>this</markup> is my <markup>string</markup>'

\b确保只匹配完整的单词。

因此,如果您有一个需要标记的单词列表,可以执行以下操作:

>>> mywords = ["this", "string", "words"]
>>> myre = r"\b(" + "|".join(mywords) + r")\b"
>>> re.sub(myre, r"<markup>\1</markup>", "this is my string with many words!")
'<markup>this</markup> is my <markup>string</markup> with many <markup>words</markup>!'

对于示例中的常量regexp,请执行

re.sub("(this)(.*)(string)",
       r'<markup>\1</markup>\2<markup>\3</markup>',
       text)

请注意,如果您不想丢失它,还需要将*括在括号中。

现在如果你不知道regexp是什么样子的,那就比较困难,但应该是可行的。

pattern = "(this)(.*)(string)"
re.sub(pattern,
       lambda m: ''.join('<markup>%s</markup>' % s if n % 2 == 0
                         else s for n, s in enumerate(m.groups())),
       text)

如果您的模式匹配的第一个内容不一定要标记,则使用此选项,第一个组可以选择匹配一些应该单独使用的前缀文本:

pattern = "()(this)(.*)(string)"
re.sub(pattern,
       lambda m: ''.join('<markup>%s</markup>' % s if n % 2 == 1
                         else s for n, s in enumerate(m.groups())),
       text)

你明白了。

如果您的regexp很复杂,并且您不确定是否可以将所有内容都作为一个组的一部分,而只需要标记第二个组,则可以使用更复杂的函数执行更聪明的操作:

pattern = "(this).*(string)"
def replacement(m):
    s = m.group()
    n_groups = len(m.groups())
    # assume groups do not overlap and are listed left-to-right
    for i in range(n_groups, 0, -1):
        lo, hi = m.span(i)
        s = s[:lo] + '<markup>' + s[lo:hi] + '</markup>' + s[hi:]
    return s
re.sub(pattern, replacement, text)

如果你需要处理重叠的组,你可以自己处理,但应该是可行的。

相关问题 更多 >