PHP递归变量替换 [英] PHP recursive variable replacement

查看:21
本文介绍了PHP递归变量替换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写代码来递归替换给定字符串中的预定义变量.变量以字符%"为前缀.以^"开头的输入字符串将被评估.

I'm writing code to recursively replace predefined variables from inside a given string. The variables are prefixed with the character '%'. Input strings that start with '^' are to be evaluated.

例如,假设一个变量数组,例如:

For instance, assuming an array of variables such as:

$vars['a'] = 'This is a string';  
$vars['b'] = '123';  
$vars['d'] = '%c';  // Note that $vars['c'] has not been defined
$vars['e'] = '^5 + %d';  
$vars['f'] = '^11 + %e + %b*2';  
$vars['g'] = '^date(\'l\')';  
$vars['h'] = 'Today is %g.';  
$vars['input_digits'] = '*****';  
$vars['code'] = '%input_digits';  

以下代码将导致:

a) $str = '^1 + %c';  
   $rc = _expand_variables($str, $vars);  
  // Result: $rc == 1 

b) $str = '^%a != NULL';  
   $rc = _expand_variables($str, $vars);  
   // Result: $rc == 1  

c) $str = '^3+%f + 3';  
   $rc = _expand_variables($str, $vars);  
   // Result: $rc == 262  

d) $str = '%h';  
   $rc = _expand_variables($str, $vars);  
   // Result: $rc == 'Today is Monday'  

e) $str = 'Your code is: %code';  
   $rc = _expand_variables($str, $vars);  
   // Result:  $rc == 'Your code is: *****'  

关于如何做到这一点的任何建议?我花了很多天试图做到这一点,但只取得了部分成功.不幸的是,我最后一次尝试产生了分段错误"!!

Any suggestions on how to do that? I've spent many days trying to do this, but only achieved partial success. Unfortunately, my last attempt managed to generate a 'segmentation fault'!!

非常感谢您的帮助!

推荐答案

请注意,没有检查循环包含,这只会导致无限循环.(例如:$vars['s'] = '%s'; ..)因此请确保您的数据没有此类结构.注释代码

Note that there is no check against circular inclusion, which would simply lead to an infinite loop. (Example: $vars['s'] = '%s'; ..) So make sure your data is free of such constructs. The commented code

    // if(!is_numeric($expanded) || (substr($expanded.'',0,1)==='0'
    //            && strpos($expanded.'', '.')===false)) {
..
    // }

可以使用或跳过.如果跳过,则引用任何替换,如果字符串 $str 稍后将被评估!但是由于 PHP 自动将字符串转换为数字(或者我应该说它尝试这样做??)跳过代码应该不会导致任何问题.请注意,不支持布尔值!(此外,PHP 没有自动转换,将诸如 'true' 或 'false' 之类的字符串转换为适当的布尔值!)

can be used or skipped. If it is skipped, any replacement is quoted, if the string $str will be evaluated later on! But since PHP automatically converts strings to numbers (or should I say it tries to do so??) skipping the code should not lead to any problems. Note that boolean values are not supported! (Also there is no automatic conversion done by PHP, that converts strings like 'true' or 'false' to the appropriate boolean values!)

    <?
    $vars['a'] = 'This is a string';
    $vars['b'] = '123';
    $vars['d'] = '%c';
    $vars['e'] = '^5 + %d';
    $vars['f'] = '^11 + %e + %b*2';
    $vars['g'] = '^date(\'l\')';
    $vars['h'] = 'Today is %g.';
    $vars['i'] = 'Zip: %j';
    $vars['j'] = '01234';
    $vars['input_digits'] = '*****';
    $vars['code'] = '%input_digits';

    function expand($str, $vars) {
        $regex = '/\%(\w+)/';
        $eval = substr($str, 0, 1) == '^';
        $res = preg_replace_callback($regex, function($matches) use ($eval, $vars) {
            if(isset($vars[$matches[1]])) {
                $expanded = expand($vars[$matches[1]], $vars);
                if($eval) {
                    // Special handling since $str is going to be evaluated ..
//                    if(!is_numeric($expanded) || (substr($expanded.'',0,1)==='0'
//                            && strpos($expanded.'', '.')===false)) {
                        $expanded = "'$expanded'";
//                    }
                }
                return $expanded;
            } else {
                // Variable does not exist in $vars array
                if($eval) {
                    return 'null';
                }
                return $matches[0];
            }
        }, $str);
        if($eval) {
            ob_start();
            $expr = substr($res, 1);
            if(eval('$res = ' . $expr . ';')===false) {
                ob_end_clean();
                die('Not a correct PHP-Expression: '.$expr);
            }
            ob_end_clean();
        }
        return $res;
    }

    echo expand('^1 + %c',$vars);
    echo '<br/>';
    echo expand('^%a != NULL',$vars);
    echo '<br/>';
    echo expand('^3+%f + 3',$vars);
    echo '<br/>';
    echo expand('%h',$vars);
    echo '<br/>';
    echo expand('Your code is: %code',$vars);
    echo '<br/>';
    echo expand('Some Info: %i',$vars);
    ?>

上面的代码假设 PHP 5.3,因为它使用了一个闭包.

The above code assumes PHP 5.3 since it uses a closure.

输出:

1
1
268
Today is Tuesday.
Your code is: *****
Some Info: Zip: 01234

对于 PHP <5.3 可以使用以下适配代码:

For PHP < 5.3 the following adapted code can be used:

function expand2($str, $vars) {
    $regex = '/\%(\w+)/';
    $eval = substr($str, 0, 1) == '^';
    $res = preg_replace_callback($regex, array(new Helper($vars, $eval),'callback'), $str);
    if($eval) {
        ob_start();
        $expr = substr($res, 1);
        if(eval('$res = ' . $expr . ';')===false) {
            ob_end_clean();
            die('Not a correct PHP-Expression: '.$expr);
        }
        ob_end_clean();
    }
    return $res;
}

class Helper {
    var $vars;
    var $eval;

    function Helper($vars,$eval) {
        $this->vars = $vars;
        $this->eval = $eval;
    }

    function callback($matches) {
        if(isset($this->vars[$matches[1]])) {
            $expanded = expand($this->vars[$matches[1]], $this->vars);
            if($this->eval) {
                // Special handling since $str is going to be evaluated ..
                if(!is_numeric($expanded) || (substr($expanded . '', 0, 1)==='0'
                        && strpos($expanded . '', '.')===false)) {
                    $expanded = "'$expanded'";
                }
            }
            return $expanded;
        } else {
            // Variable does not exist in $vars array
            if($this->eval) {
                return 'null';
            }
            return $matches[0];
        }
    }
}

这篇关于PHP递归变量替换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆