用于获取HTML表内容的正则表达式

Regular expression to get HTML table contents

本文关键字:正则表达式 获取 HTML 用于      更新时间:2023-10-16

我在这里偶然发现了一个挑战:如何在正则表达式的帮助下以HTML格式获取表的内容。假设这是我们的桌子:

<table someprop=2 id="the_table" otherprop="val">
    <tr>
        <td>First row, first cell</td>
        <td>Second cell</td>
    </tr>
    <tr>
        <td>Second row</td>
        <td>...</td>
    </tr>
    <tr>
        <td>Another row, first cell</td>
        <td>Last cell</td>
    </tr>
</table>

我已经找到了一种有效的方法,但它涉及到要分步骤执行的多个正则表达式:

  1. 获取正确的表格并将其行放在后参考1中(文档中可能有多个(:

    <table[^>]*?id="the_table"[^>]*?>(.*?)</table>

  2. 获取表中的行,并将单元格放在后引用1:中

    <tr.*?>(.*?)</tr>

  3. 最后获取后参考1:中的单元格内容

    <td.*?>(.*?)</td>

现在这一切都很好,但如果用一个花哨的正则表达式来完成这一切,那将是无限棒的。。。有人知道这是否可能吗?

确实没有一个可能的regex解决方案适用于任意数量的表数据,并将每个单元格放入单独的反向引用中。这是因为使用backreferences,您需要为要创建的每个backref都有一个不同的开放paren,而且您不知道自己有多少单元格。

使用一种或另一种类型的循环来提取数据并没有错。例如,在最后一个例子中,在Perl中,假设$tr已经包含了您需要的行:

@td = ( $tr =~ m{<td.*?>(.*?)</td>}sg );

现在$td[0]将包含第一个<td>$td[1]将包含第二个,等等。如果您想要一个二维数组,您可以将其封装在这样的循环中,以填充一个新的@cells变量:

our $table;  # assume has full table in it
my @cells;
while(my($tr) =~ $table = m{<tr.*?>(.*?)</tr>}sg) {
    push @cells, [ $tr =~ m{<td.*?>(.*?)</td>}sg ];
}

现在您可以进行二维寻址,允许$cells[0][0]等。外部显式循环一次处理一行表,内部隐式循环取出所有单元格。

这将适用于您显示的罐装样本数据。如果这对你来说足够好,那就太好了。使用它并继续前进。

这可能有什么错

然而,在你的模式中,实际上有很多关于数据内容的假设,我不知道你是否知道。首先,请注意我是如何使用/s的,这样它就不会卡在换行符上。

但主要的问题是,在这里,最小匹配并不总是你想要的。至少,不是在一般情况下。有时它们并不像你想象的那么简单,匹配得比你想要的要多,有时它们只是匹配得不够。

例如,如果字符串是:,那么像<i>(.*?)</i>这样的模式会得到比您想要的更多的结果

<i>foo<i>bar</i>ness</i>

因为您最终将匹配字符串<i>foo<i>bar</i>

另一个常见的问题(不包括不常见的问题(是,像<tag.*?>这样的模式可能匹配得太少,比如

<img alt=">more" src="somewhere">

现在,如果你在上面使用一个简单的<img.*?>,你只会捕获<img alt=">,这当然是错误的。

我认为剩下的最后一个主要问题是,在解析中必须完全忽略某些事情。这个嵌入评论的最简单的演示(也是<script><style>, andCDATA`(,因为你可以有类似的东西

<i> some <!-- secret</i>  --> stuff </i>

它会抛出类似CCD_ 18的东西。

当然,所有这些都有办法解决。一旦你完成了这项工作,并且付出了相当多的努力,你会发现你已经为自己构建了一个真正的解析器,完全有很多辅助逻辑,而不仅仅是一个模式。

即便如此,您也只能处理格式良好的输入字符串。错误恢复和软故障是完全不同的艺术。

这个答案是在知道OP需要c++的解决方案之前添加的

由于使用regex解析html在技术上是错误的,我将提供一个更好的解决方案。您可以使用js来获取数据,并将其放入二维数组中。我在示例中使用了jQuery。

var data = [];
$('table tr').each(function(i, n){
    var $tr = $(n);
    data[i] = [];
    $tr.find('td').text(function(j, text){
        data[i].push(text);
    });
});

jsfiddle的例子:http://jsfiddle.net/gislikonrad/twzM7/

编辑

如果你想要一种简单的javascript方式(不使用jQuery(,那么这可能更适合你:

var data = [];
var rows = document.getElementById('the_table').getElementsByTagName('tr');
for(var i = 0; i < rows.length; i++){
    var d = rows[i].getElementsByTagName('td');
    data[i] = [];
    for(var j = 0; j < d.length; j++){
       data[i].push(d[j].innerText);     
    }
}

这两个函数都以相同的方式返回数据。