【问题标题】:Python regex match sequential html tagsPython 正则表达式匹配顺序 html 标签
【发布时间】:2014-01-23 12:03:38
【问题描述】:

我正在尝试仅匹配 html 的 sn-p 中特定标记的连续出现。 对于测试字符串“blah <em>BAD</em> blah blah blah <em>Time</em> <em>Warner</em> <em>Satan</em>. The blah ..”,我只想匹配“时间”、“华纳”和“撒旦”(作为单独的字符串或一组,没关系)但不匹配“坏”。

到目前为止,我最接近的尝试是(<em>(?P<match>.*?)</em>[\s\.]){2,},它给了我“撒旦”。至少它似乎强制执行 2 或更多,但没有返回该匹配中的所有内容。我猜我需要一个涉及积极前瞻的解决方案,但我似乎无法解决这些问题。

我查看了其他各种相关问题,但似乎找不到合适的解决方案。大多数相关问题都只是简单地填写了说明 HTML 不应该用正则表达式解析的答案,而不是回答问题。我会对 lxml/BeautifulSoup 解决方案感到满意,只要它强制执行我的要求的顺序属性,但我对正则表达式最感兴趣,即使只是从好奇的角度来看也是如此。我知道我正在寻找的东西必须可以使用正则表达式。

感谢您的帮助和意见。

编辑:我意识到我可以通过使用更简单的方法来解决这个问题,通过将标记的所有实例与<em>(?P<match>.*?)</em> 匹配,迭代每个匹配对象并比较每个匹配的开始和结束位置。它会起作用,但我宁愿找到一个更简洁的解决方案。

【问题讨论】:

  • 您为什么要尝试使用正则表达式解析 HTML?确实,BeautifulSoup 是处理 HTML 的出色工具。
  • 所以你想匹配至少 2 个或更多标签的匹配标签序列,它们之间除了空格之外没有任何内容?
  • 我真的不明白你的要求。为什么时代,华纳应该匹配而BAD不应该?
  • @HamZa,不要以为那是他想要的。 Example.

标签: python html regex


【解决方案1】:

如果您对 re 解决方案感到好奇,它可能如下所示:

html = "blah <em>BAD</em> blah blah blah <em>Time</em> <em>Warner</em> <em>Satan</em>. The blah .."

rx = r"""(?x)          # extended mode - enable comments
    (                  # match a tag
        <em            # tag name
          [^<>]*       # maybe also attributes
        >              # open tag matched
        (              # now match the tag body
            (?<!</em)  # there must be no closing tag before a character
            .          # a body character
        ) *            # some more characters like this
        </em>          # closing tag
        \s*            # maybe some spaces after it
    ){2,}              # repeat the whole thing twice or more
"""

print re.sub(rx, r'{{\g<0>}}', html)
# blah <em>BAD</em> blah blah blah {{<em>Time</em> <em>Warner</em> <em>Satan</em>}}. The blah ..

【讨论】:

  • 谢谢!乍一看,这似乎是我正在寻找的答案。我认为我最终不会使用它(我可能会使用编辑中提到的方法),但这正是我想看到的解决方案。你介意用正则表达式的分解来更新你的答案吗?稍后我有时间再测试一下,如果我不能打破它,我会接受答案。
  • 好的,所以我玩了一下。我现在意识到我可以更清楚地了解需求,我实际上不需要支持属性。我控制着标签,它实际上不是一些随机的 html 输入。无论如何,这适用于 re.sub,但不适用于 findall。你知道为什么会这样吗?
  • @IcelandicHoney:您可能希望将整个内容包含在另一对 () 中,以便被 findall 捕获。但是您将立即获得整个区块['&lt;em&gt;Time&lt;/em&gt; &lt;em&gt;Warner&lt;/em&gt; &lt;em&gt;Satan&lt;/em&gt;']。我看不出有任何方法可以将['&lt;em&gt;Time&lt;/em&gt;', '&lt;em&gt;Warner&lt;/em&gt;', '&lt;em&gt;Satan&lt;/em&gt;'] 作为单独的匹配项。
  • 好吧,只是对 findall 在群组中的行为有点困惑。顺便说一句,我最初的尝试在 re.sub 中使用时有效(满足我的需要),但我只用 findall 进行了测试。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-08-29
  • 1970-01-01
  • 2014-04-29
  • 1970-01-01
  • 2011-12-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多