正则表达式:如何匹配任意顺序多个指定单词间的文本(含首尾)
给定一组目标单词,需要匹配文本中包含所有目标单词的最短连续文本片段(片段需包含这些单词本身)。
举个例子:
- 目标单词列表:
['word1', 'word2', 'word3'] - 待匹配文本:
Lorem ipsum dolor sit word2, consectetur adipiscing elit. word3 tristique in dolor vel consequat. Nulla tincidunt suscipit molestie. Suspendisse mauris turpis, ultricies pulvinar facilisis word1, vulputate sit amet . Donec cursus odio ut ipsum rutrum faucibus. Ut accumsan arcu ac ex scelerisque, ac sodales metus dictum. Nam efficitur velit sed lorem pharetra commodo. Morbi velit massa, feugiat nec ligula nec, finibus tincidunt nulla. Nulla a suscipit elit. Proin in nibh nec ipsum eleifend tempor.
需要匹配出的片段是:
word2, consectetur adipiscing elit. word3 tristique in dolor vel consequat. Nulla tincidunt suscipit molestie. Suspendisse mauris turpis, ultricies pulvinar facilisis word1
正则表达式方案
适合文本长度较短的场景,核心思路是通过正则确保片段包含所有目标单词,同时匹配首尾的目标单词:
import re def get_target_segment(text, target_words): # 转义单词中的正则特殊字符,避免匹配出错 escaped_words = [re.escape(word) for word in target_words] # 正向预查规则:确保片段内包含所有目标单词 lookahead_rule = '(?=.*{})'.format('.*'.join(escaped_words)) # 匹配首尾为任意目标单词的片段 segment_pattern = r'({})(.*?)({})'.format('|'.join(escaped_words), '|'.join(escaped_words)) # 组合完整正则表达式 full_pattern = lookahead_rule + segment_pattern # 查找所有符合条件的片段,取最短的那个 matches = re.findall(full_pattern, text, re.DOTALL) if matches: shortest_segment = min(matches, key=lambda x: len(''.join(x))) return ''.join(shortest_segment) return None # 示例调用 words = ['word1', 'word2', 'word3'] text = """Lorem ipsum dolor sit word2, consectetur adipiscing elit. word3 tristique in dolor vel consequat. Nulla tincidunt suscipit molestie. Suspendisse mauris turpis, ultricies pulvinar facilisis word1, vulputate sit amet . Donec cursus odio ut ipsum rutrum faucibus. Ut accumsan arcu ac ex scelerisque, ac sodales metus dictum. Nam efficitur velit sed lorem pharetra commodo. Morbi velit massa, feugiat nec ligula nec, finibus tincidunt nulla. Nulla a suscipit elit. Proin in nibh nec ipsum eleifend tempor.""" print(get_target_segment(text, words))
运行后会输出需要匹配的目标片段。
滑动窗口方案
适合处理长文本,效率更高:
- 遍历文本,记录每个目标单词出现的所有位置
- 维护一个滑动窗口,确保窗口内包含所有目标单词
- 逐步缩小窗口左边界,找到包含所有单词的最短连续片段
示例代码(Python):
def get_shortest_segment(text, target_words): from collections import defaultdict word_positions = defaultdict(list) # 记录每个目标单词的所有出现位置 for idx, word in enumerate(text.split()): if word.rstrip(',.') in target_words: word_positions[word.rstrip(',.')].append(idx) # 初始化窗口指针和最小长度 pointers = {word: 0 for word in target_words} min_length = float('inf') start_idx = end_idx = 0 while True: # 获取当前窗口内各单词的最新位置 current_positions = [word_positions[word][pointers[word]] for word in target_words] current_start = min(current_positions) current_end = max(current_positions) current_length = current_end - current_start # 更新最小片段 if current_length < min_length: min_length = current_length start_idx = current_start end_idx = current_end # 移动最早出现的单词的指针 earliest_word = target_words[current_positions.index(current_start)] pointers[earliest_word] += 1 # 如果某个单词的指针超出其出现次数,终止循环 if pointers[earliest_word] >= len(word_positions[earliest_word]): break # 拼接结果片段 text_words = text.split() return ' '.join(text_words[start_idx:end_idx+1]) # 示例调用 words = ['word1', 'word2', 'word3'] text = """Lorem ipsum dolor sit word2, consectetur adipiscing elit. word3 tristique in dolor vel consequat. Nulla tincidunt suscipit molestie. Suspendisse mauris turpis, ultricies pulvinar facilisis word1, vulputate sit amet . Donec cursus odio ut ipsum rutrum faucibus. Ut accumsan arcu ac ex scelerisque, ac sodales metus dictum. Nam efficitur velit sed lorem pharetra commodo. Morbi velit massa, feugiat nec ligula nec, finibus tincidunt nulla. Nulla a suscipit elit. Proin in nibh nec ipsum eleifend tempor.""" print(get_shortest_segment(text, words))
内容的提问来源于stack exchange,提问作者Khaled Ouertani

