【问题标题】:Matching Deep Nested Elements HTML With RegEx使用 RegEx 匹配深层嵌套元素 HTML
【发布时间】:2022-01-18 18:51:00
【问题描述】:

我正在处理一些 HTML 文件,我正在尝试匹配 <li> 内的 <p> 标签内 <ul>

例如:

<ul>
   <li>1</li>
   <li><p>2</p></li>
   <li>
      <ul>
         <li><p>3</p></li>
      </ul>
   </li>
</ul>

我的目标是将 &lt;p&gt; 标签(2 和 3)分别与它们最近的父标签 &lt;li&gt;&lt;ul&gt; 标签匹配。

这是我正在使用的正则表达式

/&lt;ul&gt;.*?(&lt;li.*?&gt;).*?(&lt;p.*?&gt;.*?&lt;\/p&gt;)(.*?)(&lt;\/li&gt;)/gs

当我尝试在这样的 html 中匹配时会出现问题:

<ul>
   <li>
      <ul>
         <li></li>
         <p>4</p>
      </ul>
   </li>
</ul>

它匹配&lt;p&gt;标签和更远的父&lt;li&gt;&lt;ul&gt;标签。

有人知道我该如何解决这个问题吗?

编辑:假设我需要使用正则表达式进行匹配。无论如何,我最终可能会像你们建议的那样在 JS 中使用选择器,但我仍然想知道这种模式是否有一个简单的修复方法,因为这个逻辑已经存在于我使用 Regex 的应用程序中。

【问题讨论】:

  • 您真的需要将它们与正则表达式一起使用,还是将它们放在 js 脚本中对您想要对它们进行的操作有好处?在 HTML 上使用正则表达式通常是个坏主意,您可能不需要它
  • 首先考虑使用CSS Selectors逻辑
  • 我在下面发布了我的想法。顺便说一句,您不必写.*?.* 表示 “0 或更多”,所以它已经是可选的了。
  • 用正则表达式解析html可以是error prone。如果可能,请考虑使用 (dom) 解析器。
  • @Bousha 您要达到的最终目标是什么?因为它听起来像XY problem

标签: javascript regex


【解决方案1】:

这是部分答案。

我得到的最好的结果是/&lt;ul&gt;.*?(&lt;li.*?&gt;(?:(?!&lt;li&gt;).)*?&lt;p.*?&gt;.*?&lt;\/p&gt;(?:(?!&lt;\/li&gt;).)*&lt;\/li&gt;)/gs

<ul>
   <li>1</li>
   <li><p>2</p></li>
   <li>
      <ul>
         <li><p>3</p></li>
      </ul>
   </li>
</ul>

它给出(第一个显然是错误的)

&lt;li&gt;1&lt;/li&gt; &lt;li&gt;&lt;p&gt;2&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;3&lt;/p&gt;&lt;/li&gt;

<ul>
   <li>
      <ul>
         <li></li>
         <p>4</p>
      </ul>
   </li>
</ul>

结果是

<li>
      <ul>
         <li></li>
         <p>4</p>
      </ul>
   </li>

也许有人可以进一步改进它

【讨论】:

    【解决方案2】:

    如果您的目标是修复/查找错误的 HTML? IE。不允许将&lt;p&gt; 作为&lt;ul&gt; 的直系后代;因此正则表达式,更好的方法可能是一个简单的解析器。

    如果没有;最简单的就是document.createElement + innerHTML + querySelectorAll

    如果使用正则表达式,则在匹配标签时使用否定的&lt;&gt; 作为“分隔符”,即:

    <foo[^>]*>
    
    // and
    
    [^<]*
    
    

    虽然显然不是万无一失的。为您的情况快速而肮脏:

    /<ul>[^<]*<li[^>]*>[^<]*<p[^>]*>([^<]*)/
          |       |     |
          |       |     +-- ...
          |       +-- not >
          +-- not <
    

    会因&lt;p&gt; 内的标签而崩溃(即仅取决于&lt;p&gt; ... &lt;/p&gt; 内的文本)。

    【讨论】:

      【解决方案3】:

      您已被警告在 cmets 中使用带有 HTML 的正则表达式。
      它们是正确的,层次结构意味着线性模式并不总是能找到您想要的解决方案。

      适用于有效的 HTML

      假设 HTML 仍然有效,并且您要查找的标签之间只有空格,我想出了这个:

        \s*(<li.*>)?\s*(<p.*>.*<\/p>)\s*(<\/li>)?
      
      • 这使得周围的 li 元素成为可选的,但如果它存在(至少在您的示例中)仍然会捕获它。
      • 假设其他地方都是空白,所以\s*
      • 我已将.*? 替换为.*: 你不必写.*?* 已经意味着“0 或更多”

      您可以在这里进行试验:
      https://regex101.com/r/oyNweY/1

      【讨论】:

        猜你喜欢
        • 2023-03-07
        • 1970-01-01
        • 1970-01-01
        • 2010-09-10
        • 1970-01-01
        • 2023-03-05
        • 1970-01-01
        • 1970-01-01
        • 2016-01-12
        相关资源
        最近更新 更多