我有以下字符串:
<?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);
答案 0 :(得分:1)
您无法使用正则表达式执行此操作。你需要写一个解析器!
因此,创建一个堆栈(一个数组,您可以在其中添加和删除项目。使用array_push()
array_pop()
)。
遍历标签,在堆栈上推送已知的开口标签。
当您到达结束标记时,弹出堆栈,这将告诉您需要关闭的标记。
答案 1 :(得分:0)
对于递归结构,请创建递归函数。在某种形式的伪代码中:
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;
}
这应该会给你一个有效的基本结构。