如何按原字符串顺序提取并打印匹配多正则模式的子串?
时间表达式提取与顺序输出实现
核心思路
要按原字符串中出现顺序提取目标片段,不能用原框架中“匹配到一个就跳过后续”的逻辑,而是要收集所有正则的匹配结果,记录每个结果的起始位置,最后按位置排序输出,同时处理可能的重叠匹配问题。
正则模式构建
先定义通用时间匹配模式,覆盖各种时间格式(如19、19:30、19 30、19pm、19:30 am等):
TIME_PATTERN = r'\d{1,2}(?:[:\s]\d{1,2})?(?:\s*(?:a\.?m\.?|p\.?m\.?))?'
再基于此构建三个目标正则,每个正则捕获需要输出的完整片段:
- 模式1:匹配包含两个时间的关联表达式(如
entre las 19hs y las 20 30),捕获前后两个时间片段 - 模式2:匹配带am/pm标识的时间表达式(如
las 19 15 pm) - 模式3:匹配带特定前缀的单个时间表达式(如
antes de las 14 30)
完整代码实现
import re # 通用时间匹配模式 TIME_PATTERN = r'\d{1,2}(?:[:\s]\d{1,2})?(?:\s*(?:a\.?m\.?|p\.?m\.?))?' # 定义所有正则模式及对应描述 REGEX_PATTERNS = [ # 模式1:匹配双时间关联表达式 ( re.compile( r'(entre\s+(?:las|la)\s+' + TIME_PATTERN + r'(?:\s+de\s+la\s+(?:tarde|noche|mañana))?)\s+(y\s+(?:las|la)\s+' + TIME_PATTERN + r'(?:\s+de\s+la\s+(?:tarde|noche|mañana))?)', re.IGNORECASE ), "first regex pattern" ), # 模式2:匹配带am/pm的时间表达式 ( re.compile( r'((?:las|la)\s+' + TIME_PATTERN + r'\s*(?:a\.?m\.?|p\.?m\.?)(?:\s+de\s+la\s+(?:tarde|noche|mañana))?)', re.IGNORECASE ), "second regex pattern" ), # 模式3:匹配带前缀的单个时间表达式 ( re.compile( r'((?:a\s+eso\s+de|a\s+esas\s+de|despues\s+de|antes\s+de|hasta|tipo|desde|apartir\s+de|de|a)\s+(?:las|la)\s+' + TIME_PATTERN + r'(?:\s+de\s+la\s+(?:tarde|noche|mañana))?)', re.IGNORECASE ), "third regex pattern" ) ] def extract_time_expressions(input_text): matches = [] # 遍历所有正则,收集所有匹配项及位置 for pattern, desc in REGEX_PATTERNS: for match in pattern.finditer(input_text): # 模式1有两个捕获组,分别添加 if len(match.groups()) == 2: start1, _ = match.span(1) matches.append( (start1, match.group(1), desc) ) start2, _ = match.span(2) matches.append( (start2, match.group(2), desc) ) else: start, _ = match.span(1) matches.append( (start, match.group(1), desc) ) # 按起始位置排序,保证出现顺序 matches.sort(key=lambda x: x[0]) # 过滤重叠匹配,保留先出现的完整片段 filtered_matches = [] last_end = -1 for start, text, desc in matches: current_end = start + len(text) if start >= last_end: filtered_matches.append( (text, desc) ) last_end = current_end return filtered_matches # 测试示例(替换input_text为任意示例字符串即可) if __name__ == "__main__": input_text = "quizas seria mejor ir de 06 00 am a 11 59 ya que me gusta viajar a esas horas" results = extract_time_expressions(input_text) for text, desc in results: print(f'"{text}" <--- was extracted by the {desc}')
测试说明
- 替换
input_text为任意示例字符串,即可得到符合要求的输出 - 代码通过
finditer获取每个匹配的起始位置,排序后保证输出顺序与原字符串一致 - 过滤逻辑避免了重叠匹配的重复输出,确保每个时间片段只被提取一次
内容的提问来源于stack exchange,提问作者Matt095
相关产品推荐
相关产品推荐

