【问题标题】:Regex for optional end-part of substring子字符串的可选结尾部分的正则表达式
【发布时间】:2025-12-09 02:30:01
【问题描述】:

考虑以下(高度简化的)字符串:

'a b a b c a b c a b c'

这是'a b c' 的重复模式,除了开头缺少'c'

我寻求一个正则表达式,它可以通过使用re.findall() 为我提供以下匹配项:

[('a', 'b'), ('a', 'b', 'c'), ('a', 'b', 'c'), ('a', 'b', 'c')]

因此,上面的字符串有 4 个 'a b c' 匹配 - 尽管第一个匹配是一个特殊情况,因为 'c' 丢失了。

我最简单的尝试是尝试捕获'a''b' 并为'c' 使用可选捕获:

re.findall(r'(a).*?(b).*?(c)?', 'a b a b c a b c a b c')

我明白了:

[('a', 'b', ''), ('a', 'b', ''), ('a', 'b', ''), ('a', 'b', '')]

显然,它只是忽略了c。当对'c' 使用非可选捕获时,搜索会提前跳过并在第二个'a b c' 子字符串中错过'a''b'。这会导致 3 个错误匹配:

[('a', 'b', 'c'), ('a', 'b', 'c'), ('a', 'b', 'c')]

我尝试了其他几种技术(例如,'(?<=c)'),但均无济于事。

注意:上面的字符串只是我的“真实世界”问题的一个骨架示例,其中上面的三个字母本身就是字符串(来自一个长日志文件),在我需要从中提取命名的其他字符串和换行符之间组。

我在 Windows 7 上使用 Python 3.5.2。

【问题讨论】:

  • 您需要在 re.findall 完成工作后“手动”删除空元组元素。
  • 您确定需要正则表达式来解析您的日志吗?
  • @WayneWerner 是的 :) 绝对必要。
  • 您的示例非常简单,因此很难提供可靠的答案。我相信问题在于您在 a、b 和 c 之间使用了.*? 通配符。对于初学者,请尝试使用 .+? 代替,以便惰性运算符不会导致它匹配零个字符并重新开始模式。
  • 此正则表达式格式适用于 R ^ab|abc 示例:x = "ababcabcabc" stringr::str_extract_all(x,"^ab|abc") [1] "ab" "abc" "abc" "abc" 不确定在 python 中是如何实现的。

标签: regex string python-3.x


【解决方案1】:

由于您的 abc占位符,并且您无法知道它们是单个字符、字符序列还是其他任何内容,因此您需要使用tempered greedy token 以确保该模式不会溢出到同一字符串中的其他匹配项,并且由于 c 是可选的,只需将其包装为 (?:...)? 可选的非捕获组:

(a)(?:(?!a|b).)*(b)(?:(?:(?!a|b|c).)*(c))?
   ^^^^^^^^^^^^^   ^^^ ^^^^^^^^^^^^^^    ^

regex demo

详情

  • (a) - 第 1 组捕获一些 a
  • (?:(?!a|b).)* - 一个缓和的贪婪令牌匹配任何不以 ab 序列开头的字符
  • (b) - 第 2 组捕获一些 b
  • (?: - 可选非捕获组的开始,重复 1 或 0 次
    • (?:(?!a|b|c).)* - 一个缓和的贪婪令牌,匹配任何字符,但换行符以 abc 模式开始
    • (c) - 第 3 组捕获一些 c 模式
  • )? - 可选非捕获组的结尾。

要获得你需要的元组列表,你需要使用理解自己构建它:

import re
r = r'(a)(?:(?!a|b).)*(b)(?:(?:(?!a|b|c).)*(c))?'
s = 'a b a b c a b c a b c'
# print(re.findall(r,s))
# That one is bad: [('a', 'b', ''), ('a', 'b', 'c'), ('a', 'b', 'c'), ('a', 'b', 'c')]
print([(a,b,c) if c else (a,b) for a,b,c in re.findall(r,s)])
# This one is good: [('a', 'b'), ('a', 'b', 'c'), ('a', 'b', 'c'), ('a', 'b', 'c')]

Python demo

【讨论】:

  • 谢谢。正则表达式适用于简单的事情(至少)。我认为我正在尝试做的事情不能通过有限状态机规则来完成(它似乎需要更多的分支逻辑)。我刚刚尝试了您的方法,但仍然缺少部分内容。我将寻求另一种方法。接受是因为我学到了一些新东西:-)
  • 好吧,你只发布了非常简化的示例,我试图尽可能地概括。正则表达式需要精度,并且需要精确的精确要求和规范。最好的问候。
最近更新 更多