在简化的情况下,我想从输入字符串中提取重复的数字(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']
。
谢谢。
答案 0 :(得分:4)
在匹配序列之前,您需要在后视图中进行反向引用以找到不同数字之间的边界,而不会消耗正则表达式之间几乎不支持的序列。类似于(\d)(?<!\1.)\1{2}(?!\1)
works in .NET但not 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次的数字。