Regex表示两个字符串之间最长的匹配序列



我在谷歌上搜索了我的用例,但没有发现任何有用的东西。

我不是正则表达式专家,所以如果社区里有人能帮忙,我将不胜感激。

问题:

给定一个文本文件,我想使用regex捕获两个子字符串(前缀和后缀(之间最长的字符串。请注意,这两个子字符串将始终位于文本的任何一行的开头。请参阅以下示例。

基板:

前缀=[项目1,项目1a,项目1b]
后缀=[项目2,项目2a,项目2b]

示例1:

项目1
项目2
项目1


项目2
项目1
项目2
项目1a




项目2b。。。。

预期结果:

项目1a



。。。。

为什么会出现这种结果

因为Item 1a的前缀和Item 2b的后缀匹配所有其他前缀-后缀对中它们之间的文本中最长的字符串。

示例2:

项目1
项目2
项目1


项目2
。。。。项目1
项目2
项目1a。。。。….
….
。。。。

预期结果:

项目1

。。。。

为什么会出现这种结果

这是因为这是两个字符串(前缀和后缀对(中最大的字符串,其中前缀和后缀都从行的开头开始。注意,还有另一对(Item 1a-Item 2b(,但由于Item 2b不在行的开头,我们不能考虑这个最长的序列。

我使用regex尝试过的内容:

我尝试过为上面列表中的每个前缀-后缀对使用下面的regex,但没有成功。

regexs = [r'^' + re.escape(pre) + '(.*?)' + re.escape(suf) for pre in prefixes for suf in suffixes]
for regex in regexs:
re.findall(regex, text, re.MULTLINE)

我尝试使用非正则表达式(Python字符串函数(:

def extract_longest_match(text, prefixes, suffixes):
longest_match = ''
for line in text.splitlines():
if line.startswith(tuple(prefixes)):
beg_index = text.index(line)
for suf in suffixes:
end_index = text.find(suf, beg_index+len(line))
match = text[beg_index:end_index]
if len(match) > len(longest_match ):
longest_match = match
return longest_match 

我遗漏了什么吗?

您需要

  • 构建一个正则表达式,用于匹配从最左边的起始分隔符到最左边的尾随分隔符的字符串(请参阅使用正则表达式匹配两个字符串之间的文本(
  • 确保分隔符仅在行首位置匹配
  • 使用re.DOTALL或等效选项确保.与换行字符匹配(请参阅Python regex,多行匹配模式(
  • 确保正则表达式匹配重叠的子字符串(请参见Python正则表达式查找所有重叠的匹配项(
  • 在文本中查找所有匹配项(请参阅如何在Python中查找正则表达式的所有匹配项?(
  • 获取最长的字符串(请参阅Python选择列表中最长字符串的最有效方法?(

Python演示:

import re
s="""Item 1 ....
Item 2 ....
Item 1 ....
....
....
Item 2 ....
Item 1 ....
Item 2
Item 1a ....
....
....
....
....
Item 2b ...."""
prefixes = ['Item 1', 'Item 1a', 'Item 1b']
suffixes = ['Item 2', 'Item 2a', 'Item 2b']
rx = r"(?=^((?:{}).*?^(?:{})))".format("|".join(prefixes), "|".join(suffixes))
# Or, a version with word boundaries:
# rx = r"(?=^((?:{})b.*?^(?:{})b))".format("|".join(prefixes), "|".join(suffixes))
all_matches = re.findall(rx, s, re.S | re.M)
print(max(all_matches, key=len))

输出:

Item 1a ....
....
....
....
....
Item 2

正则表达式看起来像

(?sm)(?=^((?:Item 1|Item 1a|Item 1b).*?^(?:Item 2|Item 2a|Item 2b)))

带单词边界

(?sm)(?=^((?:Item 1|Item 1a|Item 1b)b.*?^(?:Item 2|Item 2a|Item 2b)b))

请参阅regex演示。

详细信息

  • (?sm)-re.Sre.M标志
  • (?=^((?:Item 1|Item 1a|Item 1b).*?^(?:Item 2|Item 2a|Item 2b)))-一个积极的前瞻性,在任何位置都匹配,紧跟着一系列模式:
    • ^-行的开始
    • ((?:Item 1|Item 1a|Item 1b).*?^(?:Item 2|Item 2a|Item 2b))-组1(此值与re.findall一起返回(
    • (?:Item 1|Item 1a|Item 1b)-替换中的任何项目(可能,在此处)之后添加b单词边界是有意义的(
    • .*?-任意0+个字符,尽可能少
    • ^—线路起点
    • (?:Item 2|Item 2a|Item 2b)-列表中的任何选项(可能,在这里的)之后添加b单词边界也是有意义的(

最新更新