用于获取HTML表内容的正则表达式
Regular expression to get HTML table contents
我在这里偶然发现了一个挑战:如何在正则表达式的帮助下以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>
现在这一切都很好,但如果用一个花哨的正则表达式来完成这一切,那将是无限棒的。。。有人知道这是否可能吗?
确实没有一个可能的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>, and
CDATA`(,因为你可以有类似的东西
<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);
}
}
这两个函数都以相同的方式返回数据。
- 使用正则表达式regex_search在字符串中查找字符串
- 在 C++ 中使用正则表达式错误时出现问题 括号表达式中的范围无效
- C++正则表达式无限循环
- 使用正则表达式获取大括号块的列表
- 使用 boost::regex 从目录中获取带有一些正则表达式的文件名称时出现意外输出
- 正则表达式 获取两个换行符之间的文本
- 如何通过正则表达式 c++ 获取网址
- 如何使用正则表达式在 c++ 中获取 href 值
- C++正则表达式:获取子匹配的捕获组的索引
- 运行正则表达式时未选中的异常 - 从文件路径获取不带扩展名的文件名
- 用于获取函数签名的 C++ 正则表达式
- 如何获取未知数量的正则表达式匹配项
- 无法在 C++ 中使用正则表达式从字符串中获取所有子字符串
- 正则表达式:获取 CPP 函数 (c#) 的单独参数和参数类型
- C++中的Regex,从正则表达式中获取文本任何部分的字符串
- 正则表达式从字符串中获取用户名
- 正则表达式,获取两个关键字之间的整个字符串
- 从文件中获取行并用作正则表达式(regex)
- 用于获取HTML表内容的正则表达式
- c++正则表达式.获取带分隔符的字符串