Php 用正则表达式递归替换匹配标记

Php 用正则表达式递归替换匹配标记,php,regex,Php,Regex,我有以下字符串: hello world 我需要一个正则表达式将其转换为 hello world 以下代码适用于非递归标记: $x=preg_replace_callback('/.*?<\?\/\?>/',function($x){ return preg_replace('/(.*<\?([^\/][\w]+)\?>)(.*?)(<\?\/?\?>)/s', '\1\3<?/\2?>',$x[0]); },$str)

我有以下字符串:

hello world

我需要一个正则表达式将其转换为

hello world

以下代码适用于非递归标记:

$x=preg_replace_callback('/.*?<\?\/\?>/',function($x){
    return preg_replace('/(.*<\?([^\/][\w]+)\?>)(.*?)(<\?\/?\?>)/s',
          '\1\3<?/\2?>',$x[0]);
},$str);
$x=preg\u replace\u回调('/.*?/',函数($x){
返回preg_replace('/(.*)(.*?)/s',
“\1\3”,$x[0]);
}美元/平方米);

正则表达式无法执行此操作。你需要写一个解析器

因此,创建一个堆栈(一个数组,您可以在该数组的末尾添加和删除项目。使用
array\u push()
array\u pop()

遍历标记,在堆栈上推送已知的开始标记


当您找到一个结束标记时,弹出堆栈,它将告诉您需要关闭的标记。

对于递归结构,创建一个递归函数。以某种形式的伪代码:

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;
}
标记=['','']
//将消耗的流输出到“output”并返回其余的流
功能关闭\u匹配(行、输出){
用于(标记中的标记){
if line.startswith(标记){
output.append(标记)
line=close\u匹配(line.substring(tag.length()),输出)
i=行索引(“”)
…//检查j是否有错误,并检查i之间的值,j对close标记有效
output.append(closetag_for_tag(tag))
直线=直线子串(j+1)
}
}
回流线;
}

这将为您提供一个基本的工作结构。

我的眼睛。。。他们在流血…我已经决定放弃结束标记,并始终要求用户命名结束标记。这将使我更容易解析它们,当然也会快得多,因为我不需要依赖于手动遍历它们。这应该匹配任何标记,预先定义所有可能的标记是不可取的。此外,如果包含
递归的文本使用调用堆栈,这也会失败。迭代使用隐式堆栈。因为您需要解析器来解析任意嵌套层次结构。