匹配在给定时间内不断重复的反向引用

时间:2015-07-17 01:53:53

标签: python regex

在简化的情况下,我想从输入字符串中提取重复的数字(3次),但只提取3次而不是更多。

#match a backreference(\d here) 2 more times
#11222(333)34445 get matched and consumed, 
#then the current position moves to 11222333^34445
In [3]: re.findall(r'(\d)\1{2}','1122233334445')
Out[3]: ['2', '3', '4']

#try to exclude 11222(333)34445 by setting a non-backreference(?!\1)
#as a negative lookahead assertion, it skips the match of 
#11222^(333)34445, but get captured in the next position
#112223^(333)4445
In [4]: re.findall(r'(\d)\1{2}(?!\1)','1122233334445')
Out[4]: ['2', '3', '4']

#backreference cannot go before the referenced group
In [5]: re.findall(r'(?!\1)(\d)\1{2}(?!\1)','1122233334445')
---------------------------------------------------------------------------
error                                     Traceback (most recent call last)
<ipython-input-5-a5837badf5bb> in <module>()
----> 1 re.findall(r'(?!\1)(\d)\1{2}(?!\1)','1122233334445')

/usr/lib/python2.7/re.pyc in findall(pattern, string, flags)
    179 
    180     Empty matches are included in the result."""
--> 181     return _compile(pattern, flags).findall(string)
    182 
    183 if sys.hexversion >= 0x02020000:

/usr/lib/python2.7/re.pyc in _compile(*key)
    249         p = sre_compile.compile(pattern, flags)
    250     except error, v:
--> 251         raise error, v # invalid expression
    252     if not bypass_cache:
    253         if len(_cache) >= _MAXCACHE:

error: bogus escape: '\\1'

但我期望的是['2','4']

谢谢。

3 个答案:

答案 0 :(得分:4)

在匹配序列之前,您需要在后视图中进行反向引用以找到不同数字之间的边界,而不会消耗正则表达式之间几乎不支持的序列。类似于(\d)(?<!\1.)\1{2}(?!\1) works in .NETnot in Python obviously

一个想法是使用像@hwnd评论的The Great Trick。这也是一个很好的表现与获得一些可有可无的元素的缺点。找到两个不同数字之间的边界作为要求的另一个想法是捕获lookbehind

(?:^|(?<=(\d))(?!\1))(\d)\2{2}(?!\2)
  • (?:^|(?<=(\d))(?!\1))具有lookbehind的部分,用于查找不同数字之间的边界。
  • (\d)\2{2}(?!\2)第二个捕获组捕获一个数字\2。跟随相同的数字至少2x - 使用否定的lookahead再没有被相同的数字跟随。

这应该提供准确的匹配,但是解析器需要更多步骤。请参阅test at regex101

答案 1 :(得分:2)

x="1122233334445"
print [j for i,j in re.findall(r"(\d)\1{3,}|(\d)\2{2}",x) if not i]

试试这个。这会给['2', '4']

答案 2 :(得分:1)

这可能有效:

>>> re.findall(r'(\d)\1{2}', re.sub(r'(\d)\1{3,}', '',  '1122233334445'))
['2', '4']

删除重复超过3次的所有数字,然后找到重复3次的数字。