【问题标题】:Regex to get specific info from tags in HTML [closed]正则表达式从 HTML 中的标签获取特定信息 [关闭]
【发布时间】:2012-04-13 14:39:46
【问题描述】:

我有一个带有如下标记代码的 HTML 页面:

<a href="#!/series/3078/series-name">
  <span class="title">This is series # 1</span>
  <span class="info">bla bla bla</span>
</a>

<a href="#!/series/3079/series-name-2">
  <span class="title">This is series # 2</span>
  <span class="info">bla bla bla</span>
</a>

<a href="#!/series/3080/series-name-3">
  <span class="title">This is series # 3</span>
  <span class="info">bla bla bla</span>
</a>

我需要获取“/series/”之后的数字和“title”类的内部跨度的文本。

如何在 PHP 上使用正则表达式来做到这一点?

感谢您的帮助

【问题讨论】:

  • @tchrist 我不同意。 HTML 上的正则表达式基本上有一种根本不起作用的用途,即验证用户输入的 HTML 以搜索 &lt;script&gt; 标记等(参见“samy 是我的英雄”),以及一种它们非常有用的用途擅长,从 HTML 页面中获取列表等。但是,当您想从 DOM 中获取信息时,例如在这种情况下(来自 &lt;a&gt; 标记 + 来自特定子 &lt;span&gt; 的文本),则正则表达式不再适用。我会使用beautiful soup 来做到这一点,我不知道 PHP 有什么。
  • @cha0site 你可以保持尊重,但仍然是错误的,你就是这样。没有任何理由不在 HTML 上使用文本编辑器。人们总是这样做。
  • @Qtax:是的。但是,Stackoverflow 只能提供一个过时且技术上不太正确的笑话页面来解释新手的替代方案,这不是很尴尬吗?
  • @tchrist 我认为这里合适的拉丁语是 Quod licet Iovi, non licet bovi。您显然可以使用正则表达式处理任何解析。你真的在上面写了这本书。但是,当有人问“我正在尝试使用正则表达式解析 HTML,但无法弄清楚”时,正确的答案 “好的,不要那样做,改用解析器” ,而不是向正则表达式添加另一个特殊情况。因为 HTML 解析器不像正则表达式库那样普遍但几乎一样普遍,而且它们非常擅长解析 HTML。
  • @tchrist "如果他们可以在文本编辑器中使用正则表达式,他们可以在文本编辑器之外使用相同的正则表达式" - 不,这是错误的。解决方案在一种情况下是合适的,并不能使它在另一种情况下正确。文本编辑器,您正在查看一些非常具体的垃圾并希望将其转换为您想要的垃圾,这是一种上下文。一个 PHP 脚本,它位于一个网络服务器上,只处理垃圾,而不需要你手动按摩输入,是另一个上下文。正则表达式适合第一种情况,如果您对输入有所了解,则第二种情况。但一般?

标签: php html regex


【解决方案1】:

像 Pi 一样简单

这是一个 Perl 小程序,它演示了在非常规则且已知的组成的少量 HTML 上使用正则表达式是多么容易。

#!/usr/bin/env perl
$_ = do { local $/; <DATA> };    
while ( m!/series/(\d+)!g ) {
    print "Series $1: ";
    if ( m!<span class="title">(.*?)</span>!g ) {
        print $1;
    }
    print "\n";
}    
__END__
<a href="#!/series/3078/series-name">
  <span class="title">This is series # 1</span>
  <span class="info">bla bla bla</span>
</a>

<a href="#!/series/3079/series-name-2">
  <span class="title">This is series # 2</span>
  <span class="info">bla bla bla</span>
</a>

<a href="#!/series/3080/series-name-3">
  <span class="title">This is series # 3</span>
  <span class="info">bla bla bla</span>
</a>

运行时,该程序会打印出来:

Series 3078: This is series # 1
Series 3079: This is series # 2
Series 3080: This is series # 3

看看这有多容易?没什么。

同样的模式也适用于 PHP,因为我没有做任何只有 Perl 而不是 PCRE 做的事情。


另一方面...

构建会扰乱这种特殊方法的输入并不难。再说一次,弥补这一点也不难,正如我在 herehere 等其他地方展示的那样。

人们一直使用文本编辑器编辑 HTML。这是完全正常的。当他们这样做时,他们会使用正则表达式。当他们做同样的事情时,并不是一个程序被祝福而另一个程序被诅咒。想要在非文本编辑器的不同程序中执行与在文本编辑器中执行完全相同的操作并没有错。

但是,除了最简单的事情(比如这里的这个问题,这算得上非常简单)之外的所有事情,都需要权衡取舍,大多数询问如何去做的人都做不到。我对这个悖论有更长的讨论here

【讨论】:

  • 是的,如果您喜欢用正则表达式编写自己的“解析器”,这并不难。并享受处理“不太有效的 HTML”解析的所有细节。
  • @Qtax 碰巧,我很喜欢这样。但是提供的问题规范是一个非常有限的一个,一个其正则表达式解决方案是微不足道且不言自明的——而且完全足够。去写一些大规模过度设计的庞然大物来做一个完整的解析来设置整个树只是为了做我上面展示的简单提取是非常愚蠢的。 HTML 的发明并没有淘汰像grepvi 这样的长期存在的工具,并且假装不这样做对所有人都是有害的。解决手头的问题,不要过度设计,你会和家人一起吃晚饭。
  • @tchrist +1 仅用于该评论。我不怎么使用 perl,但我对正则表达式的热爱就像你这样的 perl 大师一样强烈(如果可以的话,我会使用正则表达式来做我的晚餐)。大多数叫 Tony the Pony 的人(我以前也这样做过)建议使用 XML 解析器作为替代方案,它做出了同样多的假设 — 即它是有效的 XML。任何一种解决方案都可以处理无效的 XML 和不一致的代码块,但这并不意味着 先验 说一种解决方案优于另一种解决方案。因此,如果 OP 要求使用正则表达式,为什么不给他们一个正则表达式呢?
  • @cha0site 动词后面紧跟复数名词的正则表达式是\w+/VB\S* \s+ \w+/NNP?S — 使用标准的 Penn Treebank 标签。 :) 确定性问题更难,因为 Penn 标签通常不够丰富; e.g. 指示性形容词也使名词定性。是的,我已经完成了这类工作,而这实际上是我认为您必须具有可用的完整解析结构的地方,正则表达式在任意递归的情况下很难正确地做到这一点。这并不能阻止人们在给妈妈的信或晚餐菜单上使用正则表达式 1,$s/foo/bar/g
  • @cha0site 我个人的经验法则是,如果它是我以前从未见过的 HTML,这意味着我无法直观地检查它,我总是使用解析器。如果我可以看一下,那么这取决于问题的复杂性。对于简单的 greppy 事情,我不明白为什么要打扰。
【解决方案2】:

正则表达式是否适合这项工作取决于实际工作是什么。如果您有一个大的 HTML 页面或一组 HTML 页面,并且您想从中提取信息,那么正则表达式可能是一个不错的选择。但是,如果您的输入不受您的控制,那么正则表达式就不是您想要的。

无论如何,使用 PHP 执行此操作的正确方法是使用 DOMDocument::loadHTML 解析 html,然后使用从那里得到的 DOMDocumentgetElementsByTagName 并对其进行迭代。如果您喜欢,甚至可以使用 XPath。在解析 HTML 时,这总是比正则表达式更强大的工具,除非您实际上已经在正则表达式中编写了 HTML 解析器。

【讨论】:

    【解决方案3】:

    这里:(已编辑!

    preg_match_all($links, '/\/series\/([\d]+)\/.*?<span class="title">(.*?)<\/span>/ism', $matches);
    
    var_dump($matches);
    

    希望对您有所帮助。不过,我建议在 PHP 中查看 DOMDocument。我认为这将是一个更清洁的解决方案。正则表达式往往丑陋而缓慢。

    【讨论】:

      【解决方案4】:

      如果您的标记比您发布的 sn-p 长得多,那么正则表达式就不是最佳选择,因为它的计算成本非常高。

      (无论如何,你不能用正则表达式完全解析 XML)。

      我的建议是您使用XML parser 解析标记,这样您就可以遍历它所代表的树结构。这将使您能够轻松获得所需的数据。

      如果href 属性总是看起来像#!/series/XXXX/series-name-2,那么您可以通过简单的字符串解析访问XXXX

      【讨论】:

      • 当然,您可以使用正则表达式完全解析 XML — 最好使用其中的几个和辅助逻辑来控制它们。
      • @tchrist。不,不,你不能。 XML 不是常规语言。您可能想阅读正则语言理论。
      • 不要教你的奶奶吸鸡蛋。并且更仔细地阅读我写的内容,因为你完全误解了它。您当然可以并且确实可以并且确实使用正则表达式来提取令牌以对您的输入进行分类,即使该输入是 XML。你认为这些事情到底是怎么做到的?除此之外,现代模式不是你祖母的NAMBY-PAMBY 常规语言!现代模式完全等同于上下文相关的递归下降解析器,包括在php。去阅读我在答案底部的参考资料。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-10
      • 2016-09-08
      • 1970-01-01
      • 2023-03-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多