我正在尝试使用正则表达式从文本块中删除一些内容。我已准备好所有模式,但似乎无法删除重叠的两个(或更多)。
例如:
import re
r1 = r'I am'
r2 = r'am foo'
text = 'I am foo'
re.sub(r1, '', text) # Returns ' foo'
re.sub(r2, '', text) # Returns 'I '
如何同时替换两个匹配项并以空字符串结束?
我最终使用的是Ned Batchelder's answer的略微修改版本:
def clean(self, text):
mask = bytearray(len(text))
for pattern in patterns:
for match in re.finditer(pattern, text):
r = range(match.start(), match.end())
mask[r] = 'x' * len(r)
return ''.join(character for character, bit in zip(text, mask) if not bit)
答案 0 :(得分:12)
如您所示,您无法使用连续的re.sub
来电。您可以使用re.finditer
查找所有内容。每个匹配项都会为您提供一个匹配对象,该对象具有.start
和.end
属性,用于指示其位置。您可以一起收集所有这些内容,然后在最后删除字符。
这里我使用bytearray
作为可变字符串,用作掩码。它被初始化为零字节,并且我用'x'标记与任何正则表达式匹配的所有字节。然后我使用位掩码来选择要保留在原始字符串中的字符,并构建一个只包含不匹配字符的新字符串:
bits = bytearray(len(text))
for pat in patterns:
for m in re.finditer(pat, text):
bits[m.start():m.end()] = 'x' * (m.end()-m.start())
new_string = ''.join(c for c,bit in zip(text, bits) if not bit)
答案 1 :(得分:2)
不要沮丧,但简短的回答是,我非常确定你不能。你能改变你的正则表达式,以便它不需要重叠吗?
如果您仍想这样做,我会尝试跟踪原始字符串上每个匹配的开始和停止索引。然后浏览字符串,只保留不在任何删除范围内的字符?
答案 2 :(得分:1)
同样有效的解决方案来自...... Perl将正则表达式合二为一:
# aptitude install regexp-assemble
$ regexp-assemble
I am
I am foo
Ctrl + D
I am(?: foo)?
regexp-assemble会获取你想要匹配的正则表达式或字符串的所有变体 将它们合二为一。是的,它将初始问题更改为另一个问题,因为它不再是匹配重叠的正则表达式,而是将regexp与匹配组合
然后你可以在你的代码中使用它:
$ python
Python 2.7.3 (default, Aug 1 2012, 05:14:39)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import re
>>> re.sub("I am foo","I am(?: foo)?","")
''
在python中使用Regexp :: Assemble的端口会很好:)
答案 3 :(得分:1)
这是一个使用选择器迭代器在文本上使用itertools.compress
动态过滤字符串的替代方法。如果应该保留字符,则选择器返回True
。 selector_for_patterns
为每个模式创建一个选择器。选择器与all函数组合(只有当所有模式都想保留一个字符时,它应该在结果字符串中)。
import itertools
import re
def selector_for_pattern(text, pattern):
i = 0
for m in re.finditer(pattern, text):
for _ in xrange(i, m.start()):
yield True
for _ in xrange(m.start(), m.end()):
yield False
i = m.end()
for _ in xrange(i, len(text)):
yield True
def clean(text, patterns):
gen = [selector_for_pattern(text, pattern) for pattern in patterns]
selector = itertools.imap(all, itertools.izip(* gen))
return "".join(itertools.compress(text, selector))