【问题标题】:Search and replace a string within a given pattern in PHP在 PHP 中搜索和替换给定模式中的字符串
【发布时间】:2020-12-25 08:22:08
【问题描述】:

我正在尝试从给定的字符串模式生成 html,类似于插件。 共有三种模式,一个 no arg,一个 single arg 和一个 multi arg 字符串模式。我无法更改此模式,因为它来自 CMS。

{pluginName} or {pluginName=3} or {pluginName id=3|view=simple|arg999=asv}

一个例子:

<p>Hi this is a html page</p> 
<p>The following line should generate html</p>
{pluginName=3}
<p>The following line also should generate html</p>
{pluginName id=3|view=simple|arg999=asv}

我的目标是用某些东西替换那些“标签”(对于这个问题,每个处理都说不相关)。但是,我希望能够将给定的参数传递给应该处理该逻辑的类/函数。

这是我的第一次尝试,没有使用正则表达式,因为我不知道如何用它们来解决这个问题(主要是因为它们速度较慢)。

<?php
function processPlugins($text, $pos = 0, $start = '{', $end = '}') {
    $plugins = array('plugin1', 'plugin2');
    while(($pos = strpos($text, $start, $pos)) !== false) {
        $startPos = $pos;
        $pos += strlen($start);
        foreach($plugins as $plugin) {
            if(substr($text, $pos, strlen($plugin)) === $plugin
               && ($endPos = strpos($text, $end, $pos + strlen($plugin))) !== false) {
                $char = substr($text, $pos + strlen($plugin), 1); // 1 is strlen of (= or ' ')
                $pos += strlen($plugin) + 1; // 1 is strlen of (= or ' ')
                $argString = substr($text, $pos, $endPos - $pos);
                if($char === ' ') { //Multi arg
                    $params = explode('|', trim($argString));
                    $paramDict = array();
                    foreach ($params as $param) {
                        list($k, $v) = array_pad(explode('=', $param), 2, null);
                        $paramDict[$k] = $v;
                    }
                    //$output = $plugin->processDictionary($paramDict);
                    var_dump($paramDict);
                } elseif ($char === '=') { //One arg
                    //$output = $plugin->processArg($argString); 
                    echo $argString . "\n";
                } elseif ($char === $end) { //No arg
                    //$output = $plugin->processNoArg();
                    echo $plugin. "\n";
                }
                $pos = $endPos + strlen($end);
                break;
            }
        }
    }
}

processPlugins('{plugin1}');
processPlugins('{plugin2=3}');
processPlugins('{plugin2 arg1=b|arg2=d}');

前面的代码在 PHP 沙箱中工作。

这段代码似乎可以工作(目前),但看起来很粗略。你会以不同的方式处理这个问题吗?我可以以某种方式重构这段代码吗?

【问题讨论】:

    标签: php regex replace


    【解决方案1】:

    此版本适用于具有多个插件令牌的输入。

    function processPlugins($text, $pos = 0, $start = '{', $end = '}') {
      $processed = [];
      $t = substr($text, $pos);
      $parts = explode($start, $t);
      array_shift($parts);
      foreach($parts as $part) {
        $pparts = explode($end, $part);
        $t = trim($pparts[0]);
        $t = str_replace(['plugin1', 'plugin2'], '', $t);
        $n = strlen($t);
        if(!$n) {
          $processed[] = trim($pparts[0]);
          continue;
        }
        $params = explode('|', $t);
        $kv = [];
        foreach($params as $p) {
          list($k, $v) = explode('=', trim($p));
          if(trim($k) === '') {
            $processed[] = trim($v);
            continue 2;
          }
          $kv[trim($k)] = trim($v);
        }
        $processed[] = $kv;  
      }
      return $processed;
    }
    
    function test($case) {
      $p = processPlugins($case);
      echo "$case => " . json_encode($p) . PHP_EOL;
    }
    
    $cases = [
      '{plugin1}',
      '{plugin2=3}',
      '{plugin2 arg1=b|arg2=d}',
      'text here {plugin1} and more{plugin2=55}here {plugin2 arg1=b|arg2=d} till the end'
    ];
    foreach($cases as $case) {
      test($case);
    }
    

    输出:

    {plugin1} => ["plugin1"]
    {plugin2=3} => ["3"]
    {plugin2 arg1=b|arg2=d} => [{"arg1":"b","arg2":"d"}]
    text here {plugin1} and more{plugin2=55}here {plugin2 arg1=b|arg2=d} till the end => ["plugin1","55",{"arg1":"b","arg2":"d"}]
    

    【讨论】:

      【解决方案2】:

      如果您选择字符串操作函数而不是正则表达式,为什么不使用explode 将输入剥离到重要部分?

      这是一个替代实现:

      function processPlugins($text, $pos = 0, $start = '{', $end = '}') {
        
        $t = substr($text, $pos);
        if($pos > 0) {
          echo "$pos chracters removed from the begining: $t" . PHP_EOL;
        } else {
          echo "Starting with '$t'" . PHP_EOL;
        }
        
        $parts = explode($start, $t);
        $t = $parts[1];
        
        $parts = explode($end, $t);
        $t = $parts[0];
      
        echo "The part between curly braces: '$t'" . PHP_EOL;
        
        $t = str_replace(['plugin1', 'plugin2'], '', $t);
        
        echo "After plugin name has been removed: '$t'" . PHP_EOL;
        
        $n = strlen($t);  
        if(!$n) {
          echo "Processing complete: " . trim($parts[0]) . PHP_EOL . PHP_EOL;
          return;
        }
        
        $params = explode('|', $t);
        echo 'Key-Values: ' . json_encode($params) . PHP_EOL;
        
        
        $kv = [];
        foreach($params as $p) {
          list($k, $v) = explode('=', trim($p));
          echo "    Item: '$p', Key: '$k', Value: '$v'" . PHP_EOL;
          
          if($k === '') {
            echo "Processing complete: $v" . PHP_EOL . PHP_EOL;
            return;
          }
          
          $kv[$k] = $v;
          
        }
        
        echo "Processing complete: " . json_encode($kv) . PHP_EOL . PHP_EOL;  
        
      }
      
      echo '<pre>';
      processPlugins('{plugin1}');
      processPlugins('{plugin2=3}');
      processPlugins('{plugin2 arg1=b|arg2=d}');
      

      当然可以丢弃回声线。有了它们,我们得到了这个输出:

      Starting with '{plugin1}'  
      The part between curly braces: 'plugin1'  
      After plugin name has been removed: ''  
      Processing complete: plugin1 
       
      Starting with '{plugin2=3}' 
      The part between curly braces: 'plugin2=3'
      After plugin name has been removed: '=3' 
      Key-Values: ["=3"]
          Item: '=3', Key: '', Value: '3' 
      Processing complete: 3
      
      Starting with '{plugin2 arg1=b|arg2=d}' 
      The part between curly braces: 'plugin2 arg1=b|arg2=d' 
      After plugin name has been removed: 'arg1=b|arg2=d' 
      Key-Values: [" arg1=b","arg2=d"]
          Item: ' arg1=b', Key: 'arg1', Value: 'b'
          Item: 'arg2=d', Key: 'arg2', Value: 'd' 
      Processing complete: {"arg1":"b","arg2":"d"}
      

      【讨论】:

      • 感谢您的建议,但是当存在多个插件时,此方法会失败。例如:processPlugins('&lt;p&gt;teste&lt;/p&gt;{plugin1}{plugin2}'); 提供的示例必须有效。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-26
      • 1970-01-01
      • 1970-01-01
      • 2017-01-11
      • 2017-01-10
      相关资源
      最近更新 更多