Python 正则表达式负向前查
我们正在解析由自动脚本生成的日志。我们关心的一个典型字符串是:'1.10.07-SNAPSHOT (1.10.07-20110303.024749-7)'
,它来自以下这一行:
15:28:02.115 - INFO - TestLib: Successfully retrieved build version: '1.11.11-SNAPSHOT (1.11.11-20110303.024749-7)'
问题是,有些日志是手动创建的,用户自己输入这些信息。为了提醒自己格式,他们添加了一个带有模板的对话框:
02:24:50.655 - INFO - gui: Step Dialog: For test results management purposes, specify the build in which the test is executed in the following format, build version: 'specify version here'
02:25:04.905 - INFO - gui: Response: OK
02:25:04.905 - INFO - gui: Comments: 'build version: '1.11.11''
我目前使用的正则表达式是 .*[Bb]uild [Vv]ersion:*\s*(?!.*<)'?([^']*)'
。其中的 '(?!.*<)'
是我最初尝试避免这个问题的,因为有些用户会写空字符串。但这并没有捕捉到上面的情况。我认为正确的做法应该是使用一个负向前查找,这样如果这一行中出现 'Step Dialog'
就不匹配,但我写这个的尝试似乎都失败了,按照regexr的说法(出于某种原因,它不让我分享我保存的表单链接)。我以为负向前查找应该像这样:(?<!Step Dialog)
,结果是这样的:
`(?<!Step Dialog).*[Bb]uild [Vv]ersion:*\s*(?!.*<)'?([^']*)'`
但不知为何,这样匹配到了上面第一行和第三行。
编辑:
'[Bb]' 和 ':\s' 是为了处理那些格式不太正确的用户输入,比如使用了多个冒号和空格,或者把 'Build' 写成大写。对于如何清理这些内容的建议非常欢迎,我对正则表达式还比较陌生。
2 个回答
有几种方法可以做到这一点,但你已经很接近了。
`.*(?<!Step Dialog.*)[Bb]uild [Vv]ersion:*\s*(?!.*<)'?([^']*)'`
`^(?!.*Step Dialog).*[Bb]uild [Vv]ersion:*\s*(?!.*<)'?([^']*)'`
Chriszuma 的模式也应该可以用。你可以选择你最喜欢的那个。如果你在意性能,可以对这三种模式进行测试,看看哪个更快。我觉得可能以 ``.(?)` 开头的那个会更快,但我不能确定。
补充一下:正如 ekhumoro 指出的,Python 的正则表达式引擎要求固定长度的回顾模式,所以第一个方法在 Python 中是行不通的。不过第二个应该没问题。
你已经接近了,但它仍然在匹配,因为它可以找到一个符合 .*
的字符串,而这个字符串前面并没有 Step Dialog
。正向和负向断言只会影响它们周围的模式。因此,你需要强制它检查每一个你不想匹配 Step Dialog
的字符。
试试这个:
`^(?:(?!Step Dialog).)*[Bb]uild [Vv]ersion:*\s*(?!.*<)'?([^']*)'`
现在,它确保从 ^
(行的开头)到 [Bb]uild [Vv]ersion
之间的每一个字符都不是字符串 Step Dialog
。
你会注意到我还把它改成了正向前瞻,因为这样更容易理解发生了什么。