dpqy77560 2010-07-13 20:10
浏览 43
已采纳

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';  

The following code would result in:

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'!!

Help would be much appreciated!

  • 写回答

3条回答 默认 最新

  • dpmpa26468 2010-07-13 20:53
    关注

    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)) {
    ..
        // }
    

    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);
        ?>
    

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

    Output:

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

    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];
            }
        }
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥15 使用C#,asp.net读取Excel文件并保存到Oracle数据库
  • ¥15 C# datagridview 单元格显示进度及值
  • ¥15 thinkphp6配合social login单点登录问题
  • ¥15 HFSS 中的 H 场图与 MATLAB 中绘制的 B1 场 部分对应不上
  • ¥15 如何在scanpy上做差异基因和通路富集?
  • ¥20 关于#硬件工程#的问题,请各位专家解答!
  • ¥15 关于#matlab#的问题:期望的系统闭环传递函数为G(s)=wn^2/s^2+2¢wn+wn^2阻尼系数¢=0.707,使系统具有较小的超调量
  • ¥15 FLUENT如何实现在堆积颗粒的上表面加载高斯热源
  • ¥30 虚心请教几个问题,小生先有礼了
  • ¥30 截图中的mathematics程序转换成matlab