使用正则表达式将递归标签转换为数组


Convert recursive tags into array with regular expression

我有以下文字

hello <?tag?> world <?tag2?> xx <?/tag2?> hello <?/tag?> world

我需要将其转换为

数组( "你好", 数组( "世界", 数组( 'xx' ), '你好' ), "世界");

标签

是字母数字,只要它们用匹配的标签闭合,或者<?/?> .具有相同名称的标记可能会重复,但不会彼此内部。

我的问题是哪种方式是 CPU 效率最高?

  • 将递归preg_replace与回调一起使用
  • 将preg_match_all与PREG_OFFSET_CAPTURE一起使用
  • 使用 preg_split 扁平化所有标签 (PREG_SPLIT_NO_EMPTY |PREG_SPLIT_DELIM_CAPTURE),进入线性阵列,然后遍历并分组标签。

如果你也能提供表达,我会很高兴。

结果不是那么简单,但希望这对其他人有所帮助。最大的复杂功能是从preg_replace的回调函数返回非字符串。

感谢所有试图帮助的人!

class Parser {
    public $ret=array();
    function loadTemplateFromString($str){
        $this->parsed_template=$this->tags=array();
        if(!$str){
            return;
        }
        var_dump($str);
        /* First expand self-closing tags <?$tag?> -> <?tag?><?/tag?> */
        $str=preg_replace('/<'?'$(['w]+)'?>/','<?'1?><?/'1?>',$str);
        /* Next fix short ending tag <?tag?>  <?/?> -> <?tag?>  <?/?> */
        $x=preg_replace_callback('/.*?<'?'/'?>/',function($x){
                return preg_replace('/(.*<'?([^'/]['w]+)'?>)(.*?)(<'?'/?'?>)/',
                   ''1'3<?/'2?>',$x[0]);
                },$str);
        /* Finally recursively build tag structure */
        $this->recursiveReplace($x);
    }
    function recursiveReplace($x){
        if(is_array($x)){
            // Called recursively
            $tmp2=$this->ret;$this->ret=array();
        }else{
            $x=array(4=>$x);
            $tmp2=null;
        }
        $y=preg_replace_callback('/(.*?)(<'?([^'/$]['w]+)'?>)(.*?)(<'?'/('3)?'?>)(.*?)/',
            array($this,'recursiveReplace'),$x[4]);
        $this->ret[]=$y;
        if($tmp2===null)return;
        $tmp=$this->ret;
        $this->ret=$tmp2;
        $this->ret[]=$x[1];
        $this->ret[]=$tmp;
        return '';
    }
}
$p=new Parser();
$p->loadTemplateFromString('bla <?name?> name <?/name?> bla bla <?$surname?> bla '.
    '<?middle?> mm <?/?> blah <?outer?> you <?inner?> are <?/?> inside <?/outer?>'.
    ' bobobo');
var_dump($p->ret);

这输出:

array
  0 => string 'bla ' (length=4)
  1 => 
    array
      0 => string ' name ' (length=6)
  2 => string ' bla bla ' (length=9)
  3 => 
    array
      0 => string '' (length=0)
  4 => string ' bla ' (length=5)
  5 => 
    array
      0 => string ' mm ' (length=4)
  6 => string ' blah ' (length=6)
  7 => 
    array
      0 => string ' you ' (length=5)
      1 => 
        array
          0 => string ' are ' (length=5)
      2 => string ' inside ' (length=8)
  8 => string ' bobobo' (length=7)

<?tag N ?>转换为 <elem N >并将其解析为 XML 怎么样?

在你

得到一个看起来像你提到的结果的原始结构后,你可以/会根据你的元素结构来验证它(即,确保项目在数字上彼此内部等)。

只需添加一个文档元素,您就可以设置以下样式表:


编辑:在这些标签与HTML混合的事实出现之后,我想我会改变我的策略。请先查看以下代码,然后再进行说明:

$data = '<b>H</b>ello <?tag?> <b>W</b>orld <?/tag?>';
$conv1 = array(
//  original => entity
    '<?tag'  => '%START-BEGIN%',
    '<?/tag' => '%START-END%'
    '?>'     => '%END-END%'
);
$conv2 = array(
//  entity          => xml
    '%START-BEGIN%' => '<element',
    '%START-END%'   => '</element'
    '%END-END%'     => '>'
);
$data = str_replace(array_keys($conv1), array_values($conv1), data);
$data = htmlentities($data, ENT_QUOTES); // encode HTML characters
$data = str_replace(array_values($conv2), array_keys($conv2), data);
$xml = '<?xml version="1.0" encoding="UTF-8"?>'.$data;
// You must apply the following function to each output text
// html_entity_decode($data,ENT_QUOTES);