php 替换字符串中的占位符变量

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15773349/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 09:56:34  来源:igfitidea点击:

Replacing Placeholder Variables in a String

phppreg-match

提问by Tyler Hughes

Just finished making this function. Basically it is suppose to look through a string and try to find any placeholder variables, which would be place between two curly brackets {}. It grabs the value between the curly brackets and uses it to look through an array where it should match the key. Then it replaces the curly bracket variable in the string with the value in the array of the matching key.

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

It has a few problems though. First is when I var_dump($matches)it puts puts the results in an array, inside an array. So I have to use two foreach()just the reach the correct data.

虽然它有一些问题。首先是当我var_dump($matches)把结果放在一个数组中,在一个数组中。所以我必须使用两个foreach()只是到达正确的数据。

I also feel like its heavy and I've been looking over it trying to make it better but I'm somewhat stumped. Any optimizations I missed?

我也觉得它很重,我一直在查看它试图让它变得更好,但我有点难住了。我错过了任何优化?

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

回答by HamZa

I think for such a simple task you don't need to use RegEx:

我认为对于这样一个简单的任务,您不需要使用 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.

回答by antichris

I hope I'm not too late to join the party — here is how I would do it:

我希望我加入聚会还不算太晚——这是我的做法:

function template_substitution($template, $data) {
    $placeholders = array_keys($data);
    foreach ($placeholders as &$placeholder) {
        $placeholder = strtoupper("{{$placeholder}}");
    }
    return str_replace($placeholders, array_values($data), $template);
}

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

And, if by any chance you could make your $variableskeys to match your placeholders exactly, the solution becomes ridiculously simple:

而且,如果您有任何机会可以使您的$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);

(See strtr()in PHP manual.)

(请参阅PHP 手册中的strtr()。)

Taking in account the nature of the PHP language, I believe that this approach should yield the best performance from all listed in this thread.

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

回答by Decent Dabbler

I think you can greatly simplify your code, with this (unless I'm misinterpreting some of the requirements):

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

$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.: if you want to remove placeholders that are not allowed from the input string, replace

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

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

with

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

回答by emma.fn2

This is the function that I use:

这是我使用的功能:

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.

Just pass it some text to search for, and an array with the replacements in.

只需向它传递一些要搜索的文本,以及一个包含替换内容的数组。

回答by user2727399

Just a heads up for future people who land on this page: All the answers (including the accepted answer) using foreachloops and/or the str_replacemethod are susceptible to replacing good ol' Johnny {STATUS}'s name with Johnny won.

只是为将来登陆此页面的人提个醒:使用foreach循环和/或str_replace方法的所有答案(包括已接受的答案)都容易将好的 ol'Johnny {STATUS}的名字替换为Johnny won.

Decent Dabbler's preg_replace_callbackapproach and U-D13's second option (but not the first) are the only ones currently posted I see that aren't vulnerable to this, but since I don't have enough reputation to add a comment I'll just write up a whole different answer I guess.

Decent Dabbler 的preg_replace_callback方法和 U-D13 的第二个选项(但不是第一个)是目前我看到的唯一一个不容易受到此影响的选项,但由于我没有足够的声誉来添加评论,我只会写下来我猜是一个完全不同的答案。

If your replacement values contain user-input, a safer solution is to use the strtrfunction instead of str_replaceto avoid re-replacing any placeholders that may show up in your values.

如果您的替换值包含用户输入,更安全的解决方案是使用该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);

Outputs: Dear John {STATUS}, we wanted to tell you that you won the competition.Whereas str_replace outputs: Dear John won, we wanted to tell you that you won the competition.

输出: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.

回答by NIck

/**
   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;