4

我正在尝试使用 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让我的其他正则表达式可以抓住-->. 这个正则表达式确实适用于普通标签,但是,由于结束标签上存在“<”并且This is text从我之前的示例中正确返回。

我知道我不能正确使用负前瞻。关于我在这里做错了什么的任何想法?我试过[^<>]+(?=-->)了,但那不匹配任何不是这种形式的评论(如普通标签)。我认为(?!-->)当它看到该模式时会停止匹配,但它似乎不像那样工作,只是继续匹配直到它看到结尾的“>”。

为上下文发布一段代码:

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)

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

4

2 回答 2

7

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

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

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

或者,在你的情况下

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

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

于 2013-06-13T14:02:19.820 回答
5

您需要使用积极的前瞻,以确保此模式领先于您的匹配。

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

如果你想让它更通用,以便它也匹配其他标签的内容,你可以在前瞻断言中使用替代:

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

在 Regexr 上查看

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

于 2013-06-13T13:56:36.280 回答