【问题标题】:Regular expression to split one big html table to several tables of 5 rows正则表达式将一个大 html 表拆分为几个 5 行的表
【发布时间】:2018-05-31 03:16:32
【问题描述】:

我正在尝试使用 regExps 进行整理,所以在途中遇到了一个问题: 问题是我有一些带有纯文本的随机 HTML 文件,只有一个表格。文字可以在表格前后,表格不包括<thead><tbody><tfoot> rowspan等。所以我需要把这个表分成几个表,每个表有 5 行,最后一个不超过 5 行,在每个表中重复原始表的第一个字符串。比如:

<table>
  <tr>
   <td>A</td><td>B</td>
  </tr>
  <tr>
   <td>A1</td><td>B1</td>
  </tr>
  <tr>
   <td>C</td><td>D</td>
  </tr>
  <tr>
   <td>E</td><td>F</td>
  </tr>
  <tr>
   <td>E1</td><td>F1</td>
  </tr>
  <tr>
   <td>E2</td><td>F2</td>
  </tr>
  <tr>
   <td>E3</td><td>F3</td>
  </tr>
  <tr>
   <td>E4</td><td>F4</td>
  </tr>
</table>

应该变成:

<table>
  <tr>
   <td>A</td><td>B</td><--!!!(not needed to be in code)-->
  </tr>
  <tr>
   <td>A1</td><td>B1</td>
  </tr>
  <tr>
   <td>C</td><td>D</td>
  </tr>
  <tr>
   <td>E</td><td>F</td>
  </tr>
  <tr>
   <td>E1</td><td>F1</td>
  </tr>
</table>
<table>
  <tr>
   <td>A</td><td>B</td><--!!!(not needed to be in code)-->
  </tr>
  <tr>
   <td>E2</td><td>F2</td>
  </tr>
  <tr>
   <td>E3</td><td>F3</td>
  </tr>
  <tr>
   <td>E4</td><td>F4</td>
  </tr>
</table>

我需要在 PHP 中使用 PCRE 来完成这些工作,包括大量模板和更改。所以我有实现的问题。现在我可以找到像这样&lt;table&gt;\s*?(&lt;tr&gt;(?:\s|.)*?&lt;\/tr&gt;) 的第一行和4 个逐行的(&lt;tr&gt;(?:\s|.)*?&lt;\/tr&gt;\s*){1,4} 但我不知道应该如何找到第二个模板的所有出现,以便我以后可以使用它们以及如何如果有&lt;/table&gt; 表结束标记,则停止搜索。所以请帮忙

编辑

问题已得到解答,因此下一级添加原始表格标签&lt;thead&gt;&lt;tbody&gt;&lt;tfoot&gt;。在输出表中应该重构原始表的结构,所以我的意思是如果原始表的第一行是&lt;thead&gt;标签的一部分,它应该在&lt;thead&gt;中是所有输出表。

【问题讨论】:

  • 也许现在只使用DOMDocument 会更容易? :)
  • 是的,它会更容易,但现在它就像一个挑战
  • 啊,事情的原理……必须……让它……工作……!!!
  • 而且我知道它不喜欢只为我用于实际项目
  • 抱歉 rus stackoverflow 不想帮助我

标签: php html regex html-table pcre


【解决方案1】:

您可以通过执行循环来实现此目的,其中每次迭代都将使用preg_replace 添加下一个“table break”(但请参阅最后的免责声明)。建议的正则表达式将找到以下组:

  • &lt;table&gt; 标记的最后一次出现及其后的第一行,或者,如果有 thead 和/或 tbody 标记,直到结束 &lt;/thead&gt; 标记,包括开头&lt;tbody&gt; 标记,如果有的话。
  • 接下来的 4 行。必须有 4 个。

然后它还会向前看,以确保至少还有一行存在。

利用该信息,可以将单个“表格中断”注入到 HTML 字符串中。

如果表有tfooter 部分(然后也应该在表的每个分区中重复),我们还没有该信息,因为它出现在输入的最后。因此,在循环开始之前,需要进行单独的解析来提取页脚。

这是假设输入在变量$html中的代码:

// Extract the footer part (if there is one) and closing table tag
preg_match("#(\s*(</tbody|<tfooter).*?)?</table>#s", $html, $tableEnd);
$tableEnd = $tableEnd[0];

// Add a table break in each iteration as long as the last partition has more than 4 rows:
while (true) {
    $res = preg_replace("#(<table(?!.*<table).*?/tr>(?:.*?/thead>)?(?:.*?<tbody>)?)((?:.*?/tr>(?=\s*<tr)){4})#s", 
                        "$1$2$tableEnd\n$1", $html);
    if (strlen($res) === strlen($html)) break;
    $html = $res;
}

echo $res;

查看它在eval.in 上运行。

主要正则表达式的解释

以下是主要正则表达式中的一些亮点:

  • #:我使用它作为正则表达式分隔符而不是 /,以避免在正则表达式本身内部转义 /。如果您需要使用/ 作为分隔符,则将每个/ 转义为\\/:一个反斜杠用于正则表达式,另一个用于在字符串文字的上下文中转义该反斜杠。

  • (?!.*&lt;table):确保在我们即将匹配的标签之后没有其他&lt;table&gt; 标签。这是一种消极的展望。

  • ((?:.*?/tr&gt;(?=\s*&lt;tr)){4}):抓取 4 行,并且正向向前看 ((?= )) 要求每一行紧跟另一行。 (?: ) 模式不会创建捕获组,但外圆括号会创建一个。

替换

如果替换只是再次注入 2 个捕获的组(即$1$2),那么什么都不会改变。额外的$tableEnd\n$1 将关闭表格(带有页脚)并通过重用第一个捕获组开始下一个。这将具有开头的&lt;table&gt; 标记,其中包括第一行和/或表格标题。

免责声明

虽然上述方法在很多情况下都有效,但很有可能破坏它,因为正则表达式不是解析/解释 HTML 的理想方式。你真的应该使用 DOM api,PHP 有一个:DOMDocument

【讨论】:

  • 非常感谢它应该可以正常工作。还有一个小问题:是否可以在没有rowspan, colspan, b, i 的情况下包含&lt;thead&gt;&lt;tbody&gt;tfoot&gt; 的使用以及仅这3 个的其他标签。
  • 当然可以,但是如果您自己先尝试一下可能会更好,现在您已经知道如何处理这个问题了。此外,最好在您的问题中添加“##edit”部分,并添加输入和所需的输出包括那些额外的标签。
  • 对问题进行了一些编辑,所以给我几个小时自己尝试一下:)
  • 好的,请告诉我进展如何。
  • 今天没有使用它的想法是在这 4 行中我们需要找到我们寻找像子掩码这样的标签之一,然后我们替换它并关闭标签,仍然无法获得如何获得关闭标签的正确位置:我认为如果我们能找到开始和结束标签,一切都很简单,但如果我们只有一侧标签,我不知道如何找到正确的位置
猜你喜欢
  • 2011-02-15
  • 2019-04-11
  • 1970-01-01
  • 1970-01-01
  • 2021-06-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-23
相关资源
最近更新 更多