web-dev-qa-db-ja.com

文字列内のプレースホルダー変数の置き換え

この関数の作成が完了しました。基本的には、文字列を調べて、2つの中括弧_{}_の間に配置されるプレースホルダー変数を見つけようとすることを想定しています。中括弧の間の値を取得し、それを使用して、キーと一致する必要がある配列を調べます。次に、文字列内の中括弧変数を、一致するキーの配列内の値に置き換えます。

ただし、いくつか問題があります。 1つ目は、I var_dump($matches)を実行すると、結果が配列内の配列に配置されます。したがって、正しいデータに到達するために2つの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.'
_
12
Tyler Hughes

このような単純なタスクでは、正規表現を使用する必要はないと思います。

$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.
31
HamZa

パーティーに参加するのに遅すぎないことを願っています—これが私がそれをする方法です:

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

そして、万が一、$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);

strtr() in PHP manual。)を参照してください。

PHP言語の性質を考慮すると、このアプローチは、このスレッドにリストされているすべてのものから最高のパフォーマンスをもたらすはずだと私は信じています。

13
U-D13

これにより、コードを大幅に簡素化できると思います(要件の一部を誤解していない限り)。

$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 ] : '';
6
Decent Dabbler

このページにアクセスする将来の人々に注意してください:foreachループおよび/またはstr_replaceメソッドを使用するすべての回答(受け入れられた回答を含む)は、古き良きものを置き換える可能性があります 'Johnny {STATUS}の名前とJohnny won

まともなDabblerのpreg_replace_callbackアプローチとU-D13の2番目のオプション(最初ではない)だけが現在投稿されており、これに対して脆弱ではないと思いますが、コメントを追加するのに十分な評判がないため、まったく違う答えを書いてみようと思います。

置換値にユーザー入力が含まれている場合、より安全な解決策は、str_replaceの代わりにstrtr関数を使用して、値に表示される可能性のあるプレースホルダーを再置換しないようにすることです。

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

3
user2727399

これは私が使用する関数です:

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.

検索するテキストと、で置換された配列を渡すだけです。

3
emma.fn2
/**
   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;
1
NIck