Pre-scriptum:我纯粹很好奇,并且知道其他非常合适的解决方案,这些解决方案不在正则表达式的范围之内。
如何匹配起始标记,直到具有可能嵌套且可能相同的标记的结束标记。所以说我已经在HTML文件中给出了:
<div class="nice">
<a href="http://www.google.com">Hello</a>
<div>World</div>
</div>
假设我想通过正则表达式替换来评论。一个人可以做一个简单的
/(<div\sclass=\"nice\">(.*)</div>)/
但是那当然会匹配到非常接近的div标签,如果漂亮的div嵌入在另一个div中,则代码会犯规。使分隔符不贪婪会使代码犯规更多,匹配到非常第一个关闭div标签。
那么任何想法?我经常想到这一点,我从来没有找到解决方案,这在正则表达式中是不可能的,还是只是我忘记了简单的事情?是不是有某种“回顾”机制?
答案 0 :(得分:6)
改为使用HTML解析器,例如Beautiful Soup,html5lib,hpricot或nokogiri
答案 1 :(得分:3)
.NET的Regex实现是为数不多的能够处理这种情况的实现之一。它提供balanced matching功能,可以使用和计算组来解析嵌套模式。
然而,这仍然不是一个完美的解决方案。例如,如果你将一个错误的html注释放入混合中,那么即使一个聪明的正则表达式与平衡匹配也会失败。因此,使用html解析器仍然会更好。
答案 2 :(得分:3)
平衡匹配似乎是非常合适的工具,并且可能可以用多种语言实现,但Perl和.NET是我所能看到的最佳尝试。由于Perl有一个最简单的例子,这里有一个(借用http://www.perl.com/pub/a/2003/06/06/regexps.html):
$paren = qr/
\(
(
[^()]+ # Not parens
|
(??{ $paren }) # Another balanced group (not interpolated yet)
)*
\)
/x;
(?? {$ paren})只是指正则表达式本身导致递归正则表达式。很漂亮,我想我应该提到我对这样的解决方案持开放态度,但当然,这根本不是一个纯粹的正则表达式例子,当然这根本不可能定义:)
答案 3 :(得分:2)
通常的建议不适用于HTML的regexp,因为HTML 不是常规的。因此,尝试使用正则表达式解析它(特别是对于像上面那样严格的事情)将会遇到困难。
答案 4 :(得分:2)
不是我建议使用它,而是:
'#\<([\w]+)([^>]*?)(([\s]*\/>)|(\>((([^\<]*?|<\!\-\-.*?\-\->)|(?R))*)\<\/\1[\s]*\>))#sm'
应该有效,匹配任何标签,可以调整以匹配特定标签。
答案 5 :(得分:1)
正如其他人所说,这通常是一个坏主意。但是你说你只是出于好奇而问,所以这就是......
使用传统的正则表达式概念无法解决您的问题,但是某些引擎(如.NET)会作弊,并通过“平衡组定义”为您提供一种方法。
这是一个教程:http://www.codeproject.com/KB/recipes/Nested_RegEx_explained.aspx
答案 6 :(得分:1)
我的javascript正则表达式解决方案(сorrectly处理嵌套标签)
算法:
</tagnameGUID>
并重复其他比赛:)
功能无法解析自动关闭代码
function get_arr_tags(txt, tag) {
function S4() {
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
}
function GUID() {
return (S4() + S4()).toUpperCase();
}
var arr = [];
if (!txt || !tag) return arr;
var r_open = null;
var r_close = null;
var guid = GUID();
r_open = RegExp('<' + tag + '\\b[^>\\/]*?>', 'gi');
r_close = RegExp('<\\s*?\/\\s*?(' + tag + ')\\b[^>]*?>', 'gi');
var m_arr = [];
for (match = r_open.exec(txt); match != null; match = r_open.exec(txt)) {
m_arr.push(match);
}
for (var i = m_arr.length - 1; i >= 0; i--) {
var last_m_open = m_arr[i];
r_close.lastIndex = 0;
var frst_m_close = r_close.exec(txt.substring(last_m_open.index));
var real_close_idx = last_m_open.index + frst_m_close.index;
var obj = {
'begin_idx': last_m_open.index,
'open_tag': last_m_open[0],
'close_tag': frst_m_close[0],
'outerHTML': txt.substring(last_m_open.index, real_close_idx + frst_m_close[0].length).replace(RegExp(guid, 'g'), ''),
'innerHTML': txt.substring(last_m_open.index + last_m_open[0].length, real_close_idx).replace(RegExp(guid, 'g'), '')
}
obj.close_tag_begin = obj.begin_idx + obj.open_tag.length + obj.innerHTML.length;
obj.end_idx = obj.close_tag_begin + obj.close_tag.length;
arr.splice(0, 0, obj);
txt = txt.substring(0, real_close_idx) +
txt.substring(real_close_idx, real_close_idx + frst_m_close[0].length)
.replace(frst_m_close[1], frst_m_close[1] + guid) +
txt.substring(real_close_idx + frst_m_close[0].length);
}
return arr;
}
用法:
var txt = '<table>' +
'<tr><td>1' +
'<table><tr><td>2' +
'<table><tr><td>3' +
'</td></tr></table><table>inner_3</table>' +
'</td></tr></table>' +
'</td></tr>' +
'</table>' +
'<table>1st</table>' +
'<table>2nd</table>';
var arr = get_arr_tags(txt, 'table');
对于你的例子:
var txt = '<div class="nice">' +
'<a href="http://www.google.com">Hello</a>' +
'<div>World</div>' +
'</div>';
var arr = get_arr_tags(txt, 'div');