【问题标题】:PHP 7.1 replace multiple values with dynamic variablesPHP 7.1 用动态变量替换多个值
【发布时间】:2018-01-11 18:12:05
【问题描述】:

我是 PHP 新手,虽然我找到了解决问题的方法,但我觉得肯定有更简单的方法可以达到相同的结果:

这是我需要做的:

我有一个这样的字符串(实际上有大约 25 个值要替换)

"We have received ##AMOUNT## ##CURRENCY## for your OrderID n. ##ORDER_ID##"

在此字符串中,我必须将
##AMOUNT## 替换为名为@9​​87654324@
##CURRENCY## 的变量值与变量$CURRENCY
##ORDER_ID## 的值与变量$ORDER_ID 的值

目前我创建了一个数组:

$flds=['AMOUNT','CURRENCY','ORDER_ID'];

我使用循环和动态变量替换:
但我已经看到 str_replace 也接受数组,因此可以构建一个更优雅(和高效)的解决方案 但是...我找不到它

可以给点提示吗?

谢谢

【问题讨论】:

  • 找不到是什么意思? php.net/manual/en/function.str-replace.php
  • 请提供一个基本的尝试...所以您需要替换字符串中的某些内容...对“字符串替换”做一个小研究,您会感到惊讶(劳伦斯·切罗内做了剧透)

标签: php arrays str-replace


【解决方案1】:

您可以使用str_replace(),如果您有任意变量,您可以使用compact() 将它们放入一个数组中。

<?php
$str = "We have received ##AMOUNT## ##CURRENCY## for your OrderID n. ##ORDER_ID##";

$AMOUNT = 123;
$CURRENCY = 'GBP';
$ORDER_ID = 20123;

$find = ['##AMOUNT##','##CURRENCY##','##ORDER_ID##'];
$replace = compact('AMOUNT', 'CURRENCY', 'ORDER_ID');

echo str_replace($find, $replace, $str);

https://3v4l.org/1E2Mm

结果:

我们收到了您的 OrderID n 的 123 英镑。 20123

如果您正在寻找一种只定义一次变量/占位符然后匹配和替换的方法,您可以这样做:

<?php
$str = "We have received ##AMOUNT## ##CURRENCY## for your OrderID n. ##ORDER_ID##";

$AMOUNT = 123;
$CURRENCY = 'GBP';
$ORDER_ID = 20123;

$find = ['AMOUNT', 'CURRENCY', 'ORDER_ID'];

echo str_replace(
    array_map(function($v){ return '##'.$v.'##'; }, $find), 
    compact(...$find), 
    $str
);

https://3v4l.org/ekHYB

【讨论】:

  • 是的,这是目标:只定义一次要替换的标签,考虑到变量名称与标签相同
【解决方案2】:

我会做一个简单的模板类来解析它,

class SimpleTemplate
{      
    protected $src;        
    protected $vars;
    
    public function __construct($src)
    {
        $this->src = $src;
    }
    
    public function assign($key, $value)
    {
        $this->vars[$key] = $value;
    }
    
    public function out()
    {
        return str_replace(array_keys($this->vars),$this->vars,$this->src);
    }        
}

$T = new SimpleTemplate("We have received ##AMOUNT## ##CURRENCY## for your OrderID n. ##ORDER_ID##");
$T->assign('##AMOUNT##', 'foo');
$T->assign('##CURRENCY##', 'bar');
$T->assign('##ORDER_ID##', 'hello');

echo $T->out();

输出:

"We have received foo bar for your OrderID n. hello"

你可以看到here live:

您可以随时扩展它并添加功能,例如从作业中删除##,并删除任何未使用的标签。等等……

基本上,它只是一个用于变量的数组管理工具。因为我们正在构建一个这样的数组:

[
  '##AMOUNT##' => 'foo',
  '##CURRENCY##' => 'bar',
  '##ORDER_ID##' => 'hello'
];

然后使用str_replace我们使用键作为搜索,值作为替换值。

如果您想从标签分配中删除##,只需更改以下内容:

public function assign($key, $value)
{
    $this->vars['##'.$key.'##'] = $value;
}

然后像这样调用:

$T->assign('AMOUNT', 'foo');

这里真正的好处是有一个类来实现你的逻辑。它保持干净和可重用。

更新

正如 @LawrenceCherone 在 cmets 中提到的那样,您可以通过使用一些神奇的方法来获得更干净的界面。

class SimpleTemplate
{      
    protected $src;
    protected $vars;
    
    public function __construct($src)
    {
        $this->src = $src;
    }
    
    public function __set($key, $value)
    {
        $this->vars['##'.strtoupper($key).'##'] = $value;
    }
    
    public function __toString()
    {
        return str_replace(array_keys($this->vars),$this->vars,$this->src);
    }     
}

$T = new SimpleTemplate("We have received ##AMOUNT## ##CURRENCY## for your OrderID n. ##ORDER_ID##");
$T->Amount = 'foo';  //any casing works because of the transforms, in __set
$T->CURRENCY = 'bar';
$T->order_id = 'hello';

echo $T; //using __toString() lets us just output the class as our result string.

特别是__set__toString。对于这个,我在key 上做了一些转换,以使其更不容易出错,也更难看。例如,对动态属性使用混合套管。通过使用strtoupper,它们可以在任何情况下输入,删除#可以避免像$T-&gt;{'##AMOUNT##'} = 'foo';这样包装它们

我要补充的最后一件事是,如果您可以拥有未分配但想要删除它们的“标签”,您可以使用此 regx 来删除它们。

    public function __toString()
    {
        $str = str_replace(array_keys($this->vars),$this->vars,$this->src);
        return preg_replace(['/##\w+##/', '/\s{2,}/'], ['', ' '], $str); //remove any left over ##{word}## tags, and compress any run-on spaces.
    } 

你可以看到这个here的例子

数组/\s{2,}/ 中的第二个只是在空格上运行并将它们压缩到一个空格,所以如果你有 4 个空格,它就会变成一个空格。它没有很好的文档记录,但 preg_replace 可以像 str_replace 一样采用数组。

这就是我建议建立一个类的原因,它为您提供了一个实现所有这些“东西”的好地方,如果您愿意,并且不必一直重写它。

【讨论】:

  • @LawrenceCherone - 这是一个很好的建议,我试图让它尽可能简单。我可以添加它。我试图避免 $T-&gt;{'##AMOUNT##'} 所以我会像 $T-&gt;AMOUNT = 'foo'; 那样做
【解决方案3】:

您可以将str_replace 函数与两个数组一起使用,一个是搜索词,另一个是替换词:

 $words = ["##AMOUNT##", "##CURRENCY##", "##ORDER_ID##"];
 $replaces = [$AMOUNT,$CURRENCY,$ORDER_ID];
 $newString = str_replace($words, $replaces, $string);
 echo $newString;

【讨论】:

  • 这会将##AMOUNT## 替换为AMOUNT。我认为 OP 不需要这个。
  • 我打赌你想到了 ["{$AMOUNT}", "{$CURRENCY}", "{$ORDER_ID}"] 用于 $replaces 数组
【解决方案4】:

str_replace 将与数组一起使用。如果$find 是一个数组并且$replace 是一个字符串,它将用$replace 中的字符串替换$find 中的所有内容,如果两者都是数组,它将用它们对应的$find[index] 替换每个对应的元素$replace[index] 示例:

$find = ["find1", "find2" ];
$replace = [ "replace1", "replace2" ];

$string = "Find find1 and find2"; 

echo str_replace($find, $replace, $string); // "Find replace1 and replace2"

但是有一个小问题,即替换是按顺序完成的。在遇到类似以下情况之前,这通常不是问题:

$find = [ "find", "find2" ];
$replace = [ "replace", "replaceXX2" ];
$string = "Find find1 and find2"; 

echo str_replace($find, $replace, $string); // "Find replace1 and replace2"

为什么?因为它会在查找“find2”之前将“find”一词和属于 find2 的“find”都替换为 replace。

如果您想避免这种情况,您可以使用strtr,如下所示:

$find = [ "find" => "replace" , "find2" => "replaceXX" ];

$string = "Find find1 and find2"; 

echo strtr($string, $find); // "Find replace1 and replaceXX"

【讨论】:

    【解决方案5】:

    @Lawrence Cherone 回答的另一种方式。也许你想使用key =&gt; value 列表。

    <?php
    $message = "We have received ##AMOUNT## ##CURRENCY## for your OrderID n. ##ORDER_ID##";
    
    $messageParameters = [
        'AMOUNT' => 83,
        'CURRENCY' => 'USD',
        'ORDER_ID' => 3271096
        ];
    
    $parsedMessage = str_replace(
        array_map(function($v){ return '##'.$v.'##'; }, array_keys($messageParameters)), 
        array_values($messageParameters), 
        $message
    );
    
    echo $parsedMessage;
    

    结果:

    We have received 83 USD for your OrderID n. 3271096
    

    https://3v4l.org/9b7lO

    【讨论】:

      【解决方案6】:

      更优雅的方式是printf函数。

      vsprintf("We have received %s %s for your OrderID n. %s", array($AMOUNT, $CURRENCY, $ORDER_ID));
      

      更多信息在这里:http://php.net/manual/en/function.vsprintf.php

      【讨论】:

      • 这将是迄今为止最优雅的解决方案.. 但是有了这个:&lt;?php $AMOUNT='123'; $CURRENCY='EUR'; $ORDER_ID='Z1234'; printf("We have received %s %s for your OrderID n. %s", [$AMOUNT, $CURRENCY, $ORDER_ID]); $a=sprintf("We have received %s %s for your OrderID n. %s", array($AMOUNT, $CURRENCY, $ORDER_ID)); echo $a; ?&gt; 我不仅在sprintf 中而且在printf 中都遇到了一些错误:Notice: Array to string conversion in C:\inetpub\wwwroot\iper_eu\admin\test\t3.php on line 5 和相同在第 6 行有 sprintf。
      • 更新了答案@Joe,您的问题(数组)的正确函数是vsprintf。测试和工作:sandbox.onlinephpfunctions.com/code/…
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-11-09
      • 1970-01-01
      • 2022-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多