正则表达式将一个大的html表拆分为多个5行的表

时间:2017-12-17 16:46:57

标签: php html regex html-table pcre

我试图使用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完成这些工作,包括大量的模板和更改。所以我在实现方面遇到了问题。现在我可以找到像这个<table>\s*?(<tr>(?:\s|.)*?<\/tr>)的第一行和4个逐行(<tr>(?:\s|.)*?<\/tr>\s*){1,4},但我不知道如何找到第二个模板的所有出现,以便我以后可以使用它们on以及如何停止搜索是否有</table>表结束标记。所以请帮忙

修改

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

1 个答案:

答案 0 :(得分:0)

您可以通过执行循环来实现此目的,其中每次迭代将添加下一个&#34;表格中断&#34;与preg_replace(但最后见免责声明)。建议的正则表达式将找到以下组:

  • <table>标记的最后一次出现以及其后的第一行,或者,如果有thead和/或tbody标记,则直至结束{{ 1}}标记,包括开头</thead>标记(如果有)。
  • 接下来的4行。必须有4个。

然后展望未来,确保至少还有一行。

通过该信息,单个&#34;表格中断&#34;可以注入HTML字符串。

如果表有一个<tbody>部分(然后也应该在表的每个分区中重复),我们将不会有这些信息,因为它发生在输入的最后。因此,在循环开始之前,需要单独解析以提取页脚。

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

$html

eval.in上看到它。

主要正则表达式

的说明

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

  • // 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; :我使用此作为正则表达式分隔符而不是#,以避免在正则表达式本身内转义/。如果你需要使用/作为分隔符,那么将每个/转义为/:一个反斜杠用于正则表达式,另一个用于在字符串文字的上下文中转义反斜杠。

  • \\/:确保我们即将匹配的标签之后没有其他(?!.*<table)标记。这是一个消极的展望。

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

替换

如果替换只会再次注入2个捕获的组(即(?: )),那么什么都不会改变。附加$1$2将关闭表(使用页脚)并通过重用第一个捕获组来启动下一个。这将包含包含第一行和/或表头的开始$tableEnd\n$1标记。

声明

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