17

刚刚完成这个功能。基本上,它假设查看一个字符串并尝试找到任何占位符变量,这些变量将放置在两个大括号之间{}。它获取大括号之间的值,并使用它来查看应该匹配键的数组。然后它将字符串中的大括号变量替换为匹配键的数组中的值。

虽然它有一些问题。首先是当我var_dump($matches)将结果放入数组中时。所以我必须使用两个foreach()来获得正确的数据。

我也觉得它很重,我一直在寻找它试图让它变得更好,但我有点难过。我错过了什么优化?

function dynStr($str,$vars) {
    preg_match_all("/\{[A-Z0-9_]+\}+/", $str, $matches);
    foreach($matches as $match_group) {
        foreach($match_group as $match) {
            $match = str_replace("}", "", $match);
            $match = str_replace("{", "", $match);
            $match = strtolower($match);
            $allowed = array_keys($vars);
            $match_up = strtoupper($match);
            $str = (in_array($match, $allowed)) ? str_replace("{".$match_up."}", $vars[$match], $str) : str_replace("{".$match_up."}", '', $str);
        }
    }
    return $str;
}

$variables = array("first_name"=>"John","last_name"=>"Smith","status"=>"won");
$string = 'Dear {FIRST_NAME} {LAST_NAME}, we wanted to tell you that you {STATUS} the competition.';
echo dynStr($string,$variables);
//Would output: 'Dear John Smith, we wanted to tell you that you won the competition.'
4

6 回答 6

42

我认为对于这样一个简单的任务,您不需要使用 RegEx:

$variables = array("first_name"=>"John","last_name"=>"Smith","status"=>"won");
$string = 'Dear {FIRST_NAME} {LAST_NAME}, we wanted to tell you that you {STATUS} the competition.';

foreach($variables as $key => $value){
    $string = str_replace('{'.strtoupper($key).'}', $value, $string);
}

echo $string; // Dear John Smith, we wanted to tell you that you won the competition.
于 2013-04-02T20:29:01.823 回答
19

我希望我加入派对还不算太晚——我会这样做:

function template_substitution($template, $data)
{
    $placeholders = array_map(function ($placeholder) {
        return strtoupper("{{$placeholder}}");
    }, array_keys($data));

    return strtr($template, array_combine($placeholders, $data));
}

$variables = array(
    'first_name' => 'John',
    'last_name' => 'Smith',
    'status' => 'won',
);

$string = 'Dear {FIRST_NAME} {LAST_NAME}, we wanted to tell you that you have {STATUS} the competition.';

echo template_substitution($string, $variables);

而且,如果您有任何机会可以使您的$variables密钥与您的占位符完全匹配,那么解决方案将变得非常简单:

$variables = array(
    '{FIRST_NAME}' => 'John',
    '{LAST_NAME}' => 'Smith',
    '{STATUS}' => 'won',
);

$string = 'Dear {FIRST_NAME} {LAST_NAME}, we wanted to tell you that you have {STATUS} the competition.';

echo strtr($string, $variables);

(参见PHP 手册中的strtr()。)

考虑到 PHP 语言的性质,我相信这种方法应该会在该线程中列出的所有方法中产生最佳性能。


编辑:在 7 年后重新审视这个答案后,我注意到我这边有一个潜在的危险疏忽,另一位用户也指出了这一点。一定要以赞成票的形式拍拍他们的后背!

如果您对此答案在此编辑之前的样子感兴趣,请查看修订历史记录

于 2013-08-16T11:13:29.700 回答
9

我认为你可以大大简化你的代码,这样(除非我误解了一些要求):

$allowed = array("first_name"=>"John","last_name"=>"Smith","status"=>"won");

$resultString = preg_replace_callback(

    // the pattern, no need to escape curly brackets
    // uses a group (the parentheses) that will be captured in $matches[ 1 ]
    '/{([A-Z0-9_]+)}/',

    // the callback, uses $allowed array of possible variables
    function( $matches ) use ( $allowed )
    {
        $key = strtolower( $matches[ 1 ] );
        // return the complete match (captures in $matches[ 0 ]) if no allowed value is found
        return array_key_exists( $key, $allowed ) ? $allowed[ $key ] : $matches[ 0 ];
    },

    // the input string
    $yourString
);

PS.:如果要从输入字符串中删除不允许的占位符,请替换

return array_key_exists( $key, $allowed ) ? $allowed[ $key ] : $matches[ 0 ];

return array_key_exists( $key, $allowed ) ? $allowed[ $key ] : '';
于 2013-04-02T20:18:04.147 回答
4

只是提醒未来登陆此页面的人:使用foreach循环和/或方法的所有答案(包括接受的答案str_replace)都容易用.Johnny won

体面的 Dabbler 的preg_replace_callback方法和 U-D13 的第二个选项(但不是第一个)是目前发布的唯一一个不受此影响的方法,但是由于我没有足够的声誉来添加评论,所以我会写出来我猜是一个完全不同的答案。

如果您的替换值包含用户输入,则更安全的解决方案是使用该strtr函数,而不是str_replace避免重新替换可能出现在您的值中的任何占位符。

$string = 'Dear {FIRST_NAME} {LAST_NAME}, we wanted to tell you that you {STATUS} the competition.';
$variables = array(
    "first_name"=>"John",
    // Note the value here
    "last_name"=>"{STATUS}",
    "status"=>"won"
);

// bonus one-liner for transforming the placeholders
// but it's ugly enough I broke it up into multiple lines anyway :)
$replacement = array_combine(
    array_map(function($k) { return '{'.strtoupper($k).'}'; }, array_keys($variables)),
    array_values($variables)
);

echo strtr($string, $replacement);

输出:Dear John {STATUS}, we wanted to tell you that you won the competition. 而 str_replace 输出:Dear John won, we wanted to tell you that you won the competition.

于 2016-07-04T04:06:55.800 回答
3

这是我使用的功能:

function searchAndReplace($search, $replace){
    preg_match_all("/\{(.+?)\}/", $search, $matches);

    if (isset($matches[1]) && count($matches[1]) > 0){
        foreach ($matches[1] as $key => $value) {
            if (array_key_exists($value, $replace)){
                $search = preg_replace("/\{$value\}/", $replace[$value], $search);
            }
        }
    }
    return $search;
}


$array = array(
'FIRST_NAME' => 'John',
'LAST_NAME' => 'Smith',
'STATUS' => 'won'
);

$paragraph = 'Dear {FIRST_NAME} {LAST_NAME}, we wanted to tell you that you {STATUS} the competition.';

// outputs: Dear John Smith, we wanted to tell you that you won the competition.

只需将一些文本传递给它以搜索,以及一个包含替换的数组。

于 2013-04-02T20:35:37.767 回答
2
/**
   replace placeholders with object
**/
$user = new stdClass();
$user->first_name = 'Nick';
$user->last_name = 'Trom';

$message = 'This is a {{first_name}} of a user. The user\'s {{first_name}} is replaced as well as the user\'s {{last_name}}.';

preg_match_all('/{{([0-9A-Za-z_]+)}}/', $message, $matches);

foreach($matches[1] as $match)
{
    if(isset($user->$match))
        $rep = $user->$match;
    else
        $rep = '';

    $message = str_replace('{{'.$match.'}}', $rep, $message);
}

echo $message;
于 2013-10-17T08:02:48.760 回答