正则表达式:匹配一个字符串到一个模式(可能不存在)

时间:2013-06-13 13:46:16

标签: python regex negative-lookahead

我正在尝试使用Python中的正则表达式解析器来解析XML文档(这是一个有限集,所以正则表达式很好!),而且我无法正确匹配注释。

这些评论的格式为<!--This is a comment-->格式,评论本身可以包含各种非字母数字字符(包括' - ')

我希望以这样的方式匹配它们,即将注释分解为以下标记:

<!--

This is a comment

-->

开始标记很容易获得,我用另一个正则表达式成功地抓住了它,但是注释正则表达式本身变得过于贪婪并从结束标记中抓取--。我希望这个正则表达式能够抓取不一定包含在注释中的字符串,所以它也应该能够<Tag>This is text</Tag>并正确地返回This is text

这是我目前用于文本的正则表达式:

[^<>]+(?!-->)

最终结果最终为This is a comment--,当我只想This is a comment时,我的其他正则表达式可以抓取-->。然而,由于'&lt;'的存在,这个正则表达式适用于普通标签。在结束标记上并正确返回前一个示例中的This is text

我知道我一定不能正确使用负向前瞻。我在这里做错了什么想法?我已经尝试了[^<>]+(?=-->),但那不符合任何不是这种形式的评论(如普通标签)。我认为(?!-->)会在看到该模式时停止匹配,但它似乎不会那样工作,只是继续匹配,直到它看到结束'&gt;'。

为上下文发布一段代码:

xml_scanner = re.Scanner([
    (r"  ",             lambda scanner,token:("INDENT", token)),
    (r"<[A-Za-z\d._]+(?!\/)>",  lambda scanner,token:("BEGINTAG", token)),
    (r"<\/[A-Za-z\d._]+(?!\/)>",  lambda scanner,token:("ENDTAG", token)),
    (r"<[A-Za-z\d._]+\/>",      lambda scanner,token:("INLINETAG", token)),
    (r"<!--",               lambda scanner,token:("BEGINCOMMENT", token)),
    (r"-->",                lambda scanner,token:("ENDCOMMENT", token)),
    (r"[^<>]+(?!-->)",         lambda scanner,token:("DATA", token)),
    (r"\r$", None),
])

for line in database_file:
    results, remainder = xml_scanner.scan(line)

这是脚本目前唯一做的事情。

2 个答案:

答案 0 :(得分:6)

你的问题是在[^<>]+(?!-->)中,只有在This is a comment--匹配后才会尝试前瞻断言,当然它会成功,因为正则表达式的位置没有-->引擎已经结束了。

因此,您必须检查字符串的每个位置的前瞻。对此的正确习惯通常是:

(?:(?!-->).)*

或者,在您的情况下

(?:(?!-->)[^<>])*

这匹配除了尖括号之外的任意数量的字符,直到-->出现或者到达字符串的结尾。

答案 1 :(得分:5)

您需要使用正面前瞻,以确保此模式位于您的匹配之前。

[^<>]+(?=-->)

如果你想让它更通用,以便它也匹配其他标签的内容,你可以在先行断言中使用一个替换:

[^<>]+(?=-->|</)

here on Regexr

如果前方有“-->”或“</”,此正则表达式将停止。