从列表编译时,Python正则表达式仅替换第一个字符

时间:2013-03-08 18:10:26

标签: python regex django

我正在创建一个django过滤器,用于从列表中将'a'标签插入到给定的字符串中。

这是我到目前为止所做的:

def tag_me(text):
    tags = ['abc', 'def', ...]
    tag_join = "|".join(tags)
    regex = re.compile(r'(?=(.))(?:'+ tag_join + ')', flags=re.IGNORECASE)
    return regex.sub(r'<a href="/tag/\1/">\1</a>', text)

示例:

tag_me('some text def')

返回:

'some text <a href="/tag/d/">d</a>'

预期:

'some text <a href="/tag/def/">def</a>'

问题出在regex.sub匹配但只返回第一个字符。我在最后一行捕获/使用\ 1的方式有问题吗?

4 个答案:

答案 0 :(得分:3)

请注意,问题中的序列(?: ...)特别关闭捕获。请参阅re documentation(约1/5至页),其中(重点已添加)说:

  

(?:...)常规括号的非捕获版本。匹配括号内的正则表达式,但在执行匹配或稍后在模式中引用后,无法检索与组匹配的子字符串

如前面的回答所述,'('+ tag_join + ')'有效,或者如果目标文本中使用了转义符,则使用建议的"|".join(re.escape(tag) for tag in tags)版本。

答案 1 :(得分:2)

您正在捕捉(.)部分,这只是一个字符。

我不确定我是否遵循正则表达式 - 简化版r'('+ tag_join + ')'适用于您的示例。

请注意,如果您的代码名称中除了字母数字字符之外的任何其他内容,您还可以执行以下操作:

tag_join = "|".join(re.escape(tag) for tag in tags)

答案 2 :(得分:2)

简单地做

import re

def tag_me(text):
    tags = ['abc', 'def']
    reg = re.compile("|".join(tags).join('()'),
                       flags=re.IGNORECASE)
    return reg.sub(r'<a href="/tag/\1/">\1</a>', text)

print '            %s' % tag_me('some text def')
print 'wanted:     some text <a href="/tag/def/">def</a>'

那是因为你写了一个未被捕获的小组(?:....),然后你必须把这个令人不安的(?=(.))放在前面。

答案 3 :(得分:1)

这应该这样做

def tag_me(text):
    tags = ['abc', 'def', ]
    tag_join = "|".join(tags)
    pattern = r'('+tag_join+')'
    regex = re.compile(pattern, flags=re.IGNORECASE)
    return regex.sub(r'<a href="/tag/\1/">\1</a>', text)