我想以这样一种方式解析text
:将带有数字的方括号前后添加到子字符串中。据我了解,正则表达式通常会消耗字符串,这意味着默认情况下不会有匹配项重叠,对吗?我该如何调整pattern_3
才能获得所需的输出?
import re
text = 'a(1)a(2)a(1)a'
pattern = '(a(?:\((\d+)\))?)'
re.findall(pattern, text)
>>> [('a(1)', '1'), ('a(2)', '2'), ('a(1)', '1'), ('a', '')]
pattern_2 = '((?:\((\d+)\))?a(?:\((\d+)\))?)'
re.findall(pattern_2, text)
>>> [('a(1)', '', '1'), ('a(2)', '', '2'), ('a(1)', '', '1'), ('a', '', '')]
pattern_3 = pattern = '((?:\((\d+)\))?a(?=(?:\((\d+)\)))?)'
re.findall(pattern_3, text)
>>> [('a', '', '1'), ('(1)a', '1', '2'), ('(2)a', '2', '1'), ('(1)a', '1', '')]
# desired output:
>>> [('a(1)', '', '1'), ('(1)a(2)', '1', '2'), ('(2)a(1)', '2', '1'), ('(1)a', '1', '')]
更新
仅使用re
寻找解决方案
答案 0 :(得分:1)
您可以尝试使用此模式(?=(\(\d+?\)[a-z]\(\d+?\)|[a-z]\(\d+?\)|\(\d+?\)[a-z]))
,该模式可以使用正向超前解决问题。
由于环顾四周是断言,因此它们是匹配的,但不消耗字符串,因此将捕获组放入其中就足够了。然后,您可以多次匹配字符串的相同部分,并通过捕获组访问这些匹配项。
在我的解决方案中,总是有一个捕获组。
请参阅以下内容以供参考:How to find overlapping matches with a regexp?
答案 1 :(得分:1)
您可以使用:
re.findall(r'(?=\(\d+\)a|a\(\d+\))(?=((?:\((\d+)\))?a(?:\((\d+)\))?)).*?a', s)
说明:
第一个前行检查a
括号之间是否至少有一个数字。
这里的第二个前瞻仅捕获您想要的内容,但是由于两个\(\d+\)
是可选的,因此需要第一个前瞻。
然后,您只需要消耗字符,直到a
与.*?a
一起使用,就可以避免两次与同一个a
匹配。
答案 2 :(得分:1)
要获得重叠的匹配,使用在超前区域内捕获组是正确的主意。
首先定义起点(零宽度)。它应该在字符串的开头,或者在左括号之前:(?:^|(?=\())
。因为我们只需要a(
...开头或(
...内或结尾即可。
这时触发超前。通过将每个部分设为可选,并在其中第二个组来提取数字,用于在前瞻(?=
... )
内部捕获的模式可能类似于((?:\((\d+)\))?a?(?:\((\d+)\))?)
。也可以通过交替使用不同的选项来实现。
(?:^|(?=\())(?=((?:\((\d+)\))?a?(?:\((\d+)\))?))
答案 3 :(得分:0)
省略括号以使解决方案更整洁,但是您可以放回它们:
text='a1a2a1a'
您必须从结果中过滤出空字符串:
re.findall(r"(?=^(a(\d)))|(?=((\d)a)$)|(?=((\d)a(\d)))",text)
Out:
[('a1', '1', '', '', '', '', ''),
('', '', '', '', '1a2', '1', '2'),
('', '', '', '', '2a1', '2', '1'),
('', '', '1a', '1', '', '', '')]
编辑: 根据@MichałTurczyn的说法,一个前瞻也可以做到:
re.findall(r"(?=^(a(\d))|((\d)a)$|((\d)a(\d)))",text)