我在这里偶然发现了一些挑战:如何在正则表达式的帮助下以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中(文档中可能有多个):
<table[^>]*?id="the_table"[^>]*?>(.*?)</table>
获取表格的行并将单元格放在后面引用1:
中 <tr.*?>(.*?)</tr>
最后在反向引用1中获取单元格内容:
<td.*?>(.*?)</td>
现在这一切都很好,但是使用一个花哨的正则表达式来完成这一切将会更加令人敬畏......有人知道这是否可能?
答案 0 :(得分:3)
确实没有可能适用于任意数量的表数据的正则表达式解决方案,并将每个单元格放入单独的后向引用中。这是因为通过反向引用,您需要为要创建的每个backref创建一个独特的开放式窗口,并且您不知道自己有多少个单元格。
使用一种或另一种循环来提取数据没有任何问题。例如,在最后一个,在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>, and
CDATA`),因为你可以有像
<i> some <!-- secret</i> --> stuff </i>
会抛出类似<i>(.*?)</i>
的内容。
当然,有很多方法可以解决这些问题。一旦你这样做了,这真的是相当多的努力,你会发现你已经构建了一个真正的解析器,完全有很多辅助逻辑,而不仅仅是一个模式。
即便如此,您只处理格式正确的输入字符串。错误恢复和轻柔失败是一种完全不同的艺术。
答案 1 :(得分:2)
在知道OP需要c ++解决方案之前添加了这个答案......
由于使用正则表达式解析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);
}
}
这两个函数都以相同的方式返回数据。