递归更换匹配标签的正则表达式
我有以下字符串:递归更换匹配标签的正则表达式
<?foo?> <?bar?> <?baz?> hello world <?/?> <?/?> <?/?>
我需要一个正则表达式将其转换成
<?foo?> <?bar?> <?baz?> hello world <?/baz?> <?/bar?> <?/foo?>
下面的代码适用于非 - 递归标签:
$x=preg_replace_callback('/.*?<\?\/\?>/',function($x){
return preg_replace('/(.*<\?([^\/][\w]+)\?>)(.*?)(<\?\/?\?>)/s',
'\1\3<?/\2?>',$x[0]);
},$str);
你不能用正则表达式来做到这一点。你需要编写一个解析器!
因此,创建一个堆栈(从最后添加和删除项目的数组,使用array_push()
array_pop()
)。
遍历标签,推动栈上已知的开启标签。
当你到一个结束标签时,弹出堆栈,它会告诉你需要关闭的标签。
为什么不能使用(?R)? – romaninsh 2011-05-13 01:45:13
因为您需要解析器来解析任意的嵌套层次结构。 http://*.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags – 2011-05-13 05:13:30
对于递归结构,请做一个递归函数。在某种形式的伪代码中:
tags = ['<?foo?>', '<?bar?>', '<?baz?>']
// output consumed stream to 'output' and return the rest
function close_matching(line, output) {
for (tag in tags) {
if line.startswith(tag) {
output.append(tag)
line = close_matching(line.substring(tag.length()), output)
i = line.indexof('<')
... // check i for not found
output.append(line.substring(0, i))
j = line.indexof('>')
... // check j for error, and check what's between i,j is valid for close tag
output.append(closetag_for_tag(tag))
line = line.substring(j + 1)
}
}
return line;
}
这应该会给你一个基本的结构。
这应该匹配任何标签,预先定义所有可能的标签不是选项。此外,这也会失败,并且包含 romaninsh 2011-05-13 01:57:19
递归使用调用堆栈。迭代使用隐式堆栈。 – 2011-05-13 05:03:15
我的眼睛......他们正在流血...... – 2011-05-13 01:31:57
我已决定放弃/?>结束标记并始终要求用户命名结束标记。这会让我更容易解析它们,速度也更快,因为我不需要依靠手动进行解析。 – romaninsh 2011-05-20 09:42:25