【问题标题】:RegEx match open tags except XHTML self-contained tagsRegEx 匹配打开的标签,XHTML 自包含标签除外
【发布时间】:2010-12-16 11:36:23
【问题描述】:

我需要匹配所有这些开始标签:

<p>
<a href="foo">

但不是这些:

<br />
<hr class="foo" />

我想出了这个并想确保我做对了。我只捕获a-z

<([a-z]+) *[^/]*?>

我相信它说:

  • 找一个小于,然后
  • 查找(并捕获)a-z 一次或多次,然后
  • 找到零个或多个空格,然后
  • 找到任意字符零次或多次,贪心,除了/,然后
  • 查找大于

我有这个权利吗?更重要的是,你怎么看?

【问题讨论】:

    标签: html regex xhtml


    【解决方案1】:

    正如许多人已经指出的那样,HTML 不是一种常规语言,因此很难解析。我对此的解决方案是使用整洁的程序将其转换为常规语言,然后使用 XML 解析器来使用结果。有很多很好的选择。我的程序是使用带有jtidy 库的Java 编写的,用于将HTML 转换为XML,然后将Jaxen 转换为xpath 为结果。

    【讨论】:

      【解决方案2】:

      虽然您无法使用正则表达式解析 HTML 的答案是正确的,但它们并不适用于此。 OP 只想用正则表达式解析一个 HTML 标记,而这可以通过正则表达式完成。

      建议的正则表达式是错误的:

      <([a-z]+) *[^/]*?>
      

      如果你在正则表达式中添加一些东西,通过回溯可以强制它匹配愚蠢的东西,比如&lt;a &gt;&gt;[^/] 太宽松了。还要注意&lt;space&gt;*[^/]* 是多余的,因为[^/]* 也可以匹配空格。

      我的建议是

      <([a-z]+)[^>]*(?<!/)>
      

      (?&lt;! ... ) 是(在 Perl 正则表达式中)否定的后视。它读作“一个的东西,最后一个可能不是/,然后是>”。

      请注意,这允许 &lt;a/ &gt; 之类的内容(就像原始的正则表达式一样),因此如果您想要更严格的内容,您需要构建一个正则表达式来匹配由空格分隔的属性对。

      【讨论】:

      • +1 指出问题不在于解析完整的 (X)HTML,而在于匹配 (X)HTML 开放标签。
      • 其他大多数答案似乎都忽略了,即 HTML 解析器可以很好地在其实现中使用正则表达式来处理部分 HTML,如果大多数解析器不这样做,我会感到惊讶.
      • 当属性值包含“>”或“/”字符时,此处给出的答案将失败。
      • 这将在包含 cmets 或 CData 部分的 HTML 上无法正常工作。如果带引号的属性包含&gt; 字符,它也将无法正常工作。我同意 OP 的建议 可以 用正则表达式来完成,但这里介绍的过于简单化了。
      • &lt;h1&gt; 标签想和你说一句话(我知道,很容易修复,但仍然如此)...
      【解决方案3】:

      试试:

      <([^\s]+)(\s[^>]*?)?(?<!/)>
      

      和你的类似,但最后一个&amp;gt;不能在斜线之后,也接受h1

      【讨论】:

      • &amp;gt; 在属性值中有效。事实上,在“规范 XML”序列化中,您不能使用 &amp;gt;。 (这并不完全相关,只是要强调属性值中的&amp;gt; 一点也不稀奇。)
      • @Kobi: 正则表达式中的感叹号(你放在末尾的那个)是什么意思?
      • @bobince:你确定吗?我不明白了,这也是有效的 HTML:&lt;div title="this tag is a &lt;div&gt;&lt;/div&gt;"&gt;hello&lt;/div&gt;
      • @MarcoDemaio - &amp;gt; 不必在属性值中转义,但 &lt; 可以。所以这将是有效的 HTML:&lt;div title="this tag is a &amp;lt;div&gt;&amp;lt;/div&gt;"&gt;hello&lt;/div&gt;
      【解决方案4】:

      我不知道您对此的确切需求,但如果您也在使用 .NET,您不能使用 Html Agility Pack 吗?

      摘录:

      这是一个 .NET 代码库,允许 您解析“网络之外”的 HTML 文件。解析器非常宽容 使用“真实世界”格式错误的 HTML。

      【讨论】:

      • CodePlex 关闭(但这个在 CodePlex 存档中)。也许更新?
      【解决方案5】:

      我之前使用了一个名为HTMLParser 的开源工具。它旨在以各种方式解析 HTML 并很好地服务于目的。它可以将 HTML 解析为不同的树节点,您可以轻松地使用它的 API 从节点中获取属性。检查一下,看看这是否对您有帮助。

      【讨论】:

        【解决方案6】:

        在我看来,您正在尝试匹配末尾没有“/”的标签。试试这个:

        <([a-zA-Z][a-zA-Z0-9]*)[^>]*(?<!/)>
        

        【讨论】:

        • 这不起作用。对于输入 '' 匹配的是 x 和 y,尽管 x 已终止。
        【解决方案7】:
        <?php
        $selfClosing = explode(',', 'area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed');
        
        $html = '
        <p><a href="#">foo</a></p>
        <hr/>
        <br/>
        <div>name</div>';
        
        $dom = new DOMDocument();
        $dom->loadHTML($html);
        $els = $dom->getElementsByTagName('*');
        foreach ( $els as $el ) {
            $nodeName = strtolower($el->nodeName);
            if ( !in_array( $nodeName, $selfClosing ) ) {
                var_dump( $nodeName );
            }
        }
        

        输出:

        string(4) "html"
        string(4) "body"
        string(1) "p"
        string(1) "a"
        string(3) "div"
        

        基本上只定义自闭的元素节点名称,将整个 html 字符串加载到 DOM 库中,抓取所有元素,循环并过滤掉非自闭的元素并对其进行操作。

        我相信你现在已经知道你不应该为此使用正则表达式。

        【讨论】:

        • 如果你正在处理真正的 XHTML,那么在 getElementsByTagName 后面加上 NS 并指定命名空间。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-06-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多