断言和可选子字符串后面的问题

时间:2010-02-16 20:49:15

标签: regex lookahead lookbehind

我正在尝试编写一些正则表达式来解析Hyperic HQ生成的警报中的信息。警报以电子邮件的形式出现,主题为:

"[HQ] !!! - Alert: My Demo Website Alert Resource: demo.myserver.net Apache Web Server State: fixed"

简而言之,我需要能够始终如一地抓住“Apache Web Server”部分,无论主机名是什么,甚至可能都不存在。我知道主机名总是会以“myserver.net”结尾。

我的正则表达式是:

/Resource:\s.*(?<=mydomain.net)?\s(.*)\s(?=State)/

我原以为这会匹配"Resource:""State:"之间的零个或多个字符,可选地跟随(但不包括)主机名。

不幸的是,它返回的是"Server",即我要匹配的位的最后一个字。无论主机名是否在字符串中,都会发生这种情况。

有人可以帮忙吗?

编辑:由Chad提供的解决方案

/Resource:\s(?:.*.myserver.net)?(.*)\sState/ 

3 个答案:

答案 0 :(得分:3)

这是我称之为过早追索到外观的反模式的一个例子。你知道你正在寻找的字符串前面是foo,然后是bar,你知道正则表达式有一些叫做lookbehinds和lookaheads的东西,所以很明显你应该使用它:

(?<=foo).*(?=bar)

当心明显;关于正则表达式很少是直观的。请记住,前瞻性是对正则表达式的一个相当晚的补充,甚至是后来的观察,但人们在他们出现之前很久就解决了这种问题。他们通过使用捕获组来做到这一点,在大多数情况下,这仍然是最好的选择:

foo(.*)bar

你的正则表达式中还有一个彻头彻尾的错误:关于lookbehind的?量词:

(?<=mydomain.net)?

EditPadPro的搜索框标记为错误,PHP也是如此; Java和.NET没有,但我相信它们应该。它没有\b*^+${3,7}更有意义。这些都是零宽度断言,这意味着它们没有任何匹配,所以通过添加量词,你试图多次匹配相同的东西(记住$与换行符不匹配,只是位置 换行符和前一个字符之间)。

没有陷入无限循环的危险,但这是一个很好的迹象表明正则表达式作者犯了错误或者误解了某些东西。当量词是可以匹配零次的量词时,尤其如此,例如?*。它使断言成为可选的,而可选的断言是一个无关的断言。在你的正则表达式中,(?<=mydomain.net)?表示“当前位置前面有mydomain.net或者不是;我不在乎。”

无论如何,乍得已经提出了一个有效的正则表达式;我只想提供一些有关你的原因的见解。当然,现场测试我的反模式。 ;)

答案 1 :(得分:2)

这似乎适合我写的测试

/Resource:\s(?:.*myserver.net)?(?<PartIWant>.*)\s(?:State)/

如果您的正则表达式引擎支持命名捕获组,它将位于命名捕获组“PartIWant”中。

编辑: 我用这两个字符串测试了这个正则表达式

[HQ] !!! - Alert: My Demo Website Alert Resource: demo.myserver.net Apache Web Server State: fixed
[HQ] !!! - Alert: My Demo Website Alert Resource: Apache Web Server State: fixed

答案 2 :(得分:1)

有时,事情可以简单完成。用你最喜欢的语言,在“myserver.net”上进行拆分,然后对第一个元素的“State:”进行拆分。例如在Python中

>>> s="""[HQ] !!! - Alert: My Demo Website Alert Resource: demo.myserver.net Apache Web Server State: fixed"""
>>> s.split("myserver.net")[-1].split("State:")[0]
' Apache Web Server '
相关问题