如何仅迭代连续模式



给定这个分号分隔的 C/Java/other 表达式

text = "func(10+3,40+5);....;func(6+7,8+9)"

我想提取func参数的位置,由 2 个添加的 illals 组成。

import re
text = "func(10+3,40+5);....;func(6+7,8+9)"
result = [(x.start(),x.end()) for x in re.finditer("d++d+,?",text)]
print(result)

给:

[(5, 10), (10, 14), (26, 30), (30, 33)]

但这不是我想要的:我想在参数不连续时停止迭代(因为我稍后会寻找下一个func,我想提取func的参数,而不是其他函数)。

在这种情况下,re.finditer会扭曲到下一个模式,跳过中间不匹配的数据。

为了做我想做的事情,我想出了一个解决方案,记住上一个匹配并检查当前匹配是否紧随其后(如果存在)。喜欢这个:

result=[]
previous_match = None
for x in re.finditer("d++d+,?",text):
    if previous_match and previous_match.end()!=x.start():
        break
    previous_match = x
    result.append((x.start(),x.end()))
print(result)

给:

[(5, 10), (10, 14)]

这就是我想要的,但我失去了列表理解,我引入了一个丑陋的内存参数。有什么更好的方法可以做到这一点吗?

只是为了把我的两分钱放进去:使用两个正则表达式不是容易得多吗?

import re
text = "func(10+3,40+5,1002+54);....;func(6+7,8+9)"
func = re.compile(r'func([^()]+)')
params = re.compile(r'd++d+,?')
result = [[p.group(0) for p in params.finditer(f.group(0))] for f in func.finditer(text)]
print(result)
# [['10+3,', '40+5,', '1002+54'], ['6+7,', '8+9']]

这样,每个元素只包含一个函数的参数。


要获得位置,我们需要添加外部起始位置作为偏移量:
import re
text = "func(10+3,40+5,1002+54);....;func(6+7,8+9)"
func = re.compile(r'func([^()]+)')
params = re.compile(r'd++d+,?')
result = [[(p.start() + f.start(), p.end() + f.start())
            for p in params.finditer(f.group(0))]
            for f in func.finditer(text)]
print(result)
# [[(5, 10), (10, 15), (15, 22)], [(34, 38), (38, 41)]]

有一些正则表达式引擎支持在最后一个匹配位置匹配的G锚点,但 python 的 re 模块不支持。

如果您使用支持G锚点的正则表达式模块,则可以使用纯正则表达式解决方案。由于G只匹配上一个匹配项或字符串的开头(但我们的第一个结果不会出现在字符串的开头),我们使用G(?:^func()?K来匹配字符串开头的func(,然后丢弃它:

import regex
for match in regex.finditer(r'G(?:^func()?Kd++d+,?', text):
    print(match.span())

否则,您将不得不求助于编写一些python代码。最简单的方法可能是只搜索第一个";"字符的字符串:

import re
for match in re.finditer(r'd++d+,?', text[:text.find(';')]):
    print(match.span())

您是否尝试过在列表中使用 iter

import re
text = "func(10+3,40+5);....;func(6+7,8+9)"
result = iter([(x.start(),x.end()) for x in re.finditer("d++d+,?",text)])

正如评论所指出的,如果没有额外的逻辑(我已经弄清楚),re 模块是不可能的,所以我必须升级到regex模块。

Stefan在评论中提供了一个答案,允许继续使用列表理解,因为它不需要任何标志。Stephan 建议在线上使用 str.split(" ")[0] 来摆脱尾随函数,我更喜欢使用 str.partition(";")[0],因为这是代码,因此函数调用必须; 结尾(如果它在下一行,没关系)

result = [(x.start(),x.end()) for x in re.finditer("d++d+,?",text.partition(";")[0])]

作为奖励,partitionsplit 略快,即使它创建了 3 个字符串,与不创建字符串以丢弃它们的纯正则表达式解决方案相比,这有点浪费。

最新更新