查找两个字符串之间的最短匹配

Posted

技术标签:

【中文标题】查找两个字符串之间的最短匹配【英文标题】:Find shortest matches between two strings 【发布时间】:2022-01-19 23:34:12 【问题描述】:

我有一个很大的日志文件,我想在两个字符串之间提取一个多行字符串:startend

以下是来自inputfile的示例:

start spam
start rubbish
start wait for it...
    profit!
here end
start garbage
start second match
win. end

应打印所需的解决方案:

start wait for it...
    profit!
here end
start second match
win. end

我尝试了一个简单的正则表达式,但它返回了来自start spam 的所有内容。这应该怎么做?

编辑:关于现实生活中计算复杂性的附加信息

实际文件大小:2GB “开始”的出现次数:~ 12 M,均匀分布 “结束”的出现次数:~800,接近文件末尾。

【问题讨论】:

好吧,如果你想在startend之间进行匹配,那么你得到start spam作为开始结果是很正常的......你能澄清一下你想要的行为吗? 【参考方案1】:

这个正则表达式应该匹配你想要的:

(start((?!start).)*?end)

使用re.findall 方法和单行修饰符re.S 获取多行字符串中的所有出现:

re.findall('(start((?!start).)*?end)', text, re.S)

查看测试here。

【讨论】:

为什么我以前从未听说过 regex101...? 关于 regex101 的好答案和演示。我缺少的关键是消极的前瞻。真的很有用。 也可以在 JS 中工作。 你能解释一下((?!start).)吗? @FrancescoBoi 见Tempered Greedy Token - What is different about placing the dot before the negative lookahead。【参考方案2】:

用代码来做——基本状态机:

open = False
tmp = []
for ln in fi:
    if 'start' in ln:
        if open:
            tmp = []
        else:
            open = True

    if open:
        tmp.append(ln)

    if 'end' in ln:
        open = False
        for x in tmp:
            print x
        tmp = []

【讨论】:

也完全有效。【参考方案3】:

这很棘手,因为默认情况下,re 模块不会查看重叠匹配。较新版本的 Python 有一个新的 regex 模块,允许重叠匹配。

https://pypi.python.org/pypi/regex

你想使用类似的东西

regex.findall(pattern, string, overlapped=True)

如果您坚持使用 Python 2.x 或其他没有 regex 的东西,仍然有可能使用一些技巧。一位才华横溢的人在这里解决了这个问题:

Python regex find all overlapping matches?

一旦你有所有可能的重叠(我想是非贪婪的)匹配,只需确定哪个是最短的,这应该很容易。

【讨论】:

我添加了一些关于日志文件实际大小的信息。在这种情况下,存储所有重叠的匹配项会超出我计算机的磁盘空间。 好吧,我链接到的解决方案返回一个迭代器,因此您实际上不需要存储所有重叠匹配,一次只需要存储一两个。但考虑到您尝试解析的文件格式,接受的解决方案可能更适合您的目的。【参考方案4】:

你可以(?s)start.*?(?=end|start)(?:end)?,然后过滤掉所有不以“end”结尾的东西。

【讨论】:

以上是关于查找两个字符串之间的最短匹配的主要内容,如果未能解决你的问题,请参考以下文章

A 和 B 的计数差异最大的最短子串

在php中查找两个字符串之间的匹配百分比?

查找四元数之间的最短旋转

使用正则表达式查找两个字符串之间的多个匹配项

尝试所有 3 位数字锁的最短字符串

通过Python中的正则表达式优化在两个列表之间查找匹配子字符串