Замена переменных-заполнителей в строке

Только что закончил эту функцию. В принципе, предположим, что нужно просмотреть строку и попытаться найти любые переменные-заполнители, которые будут размещаться между двумя фигурными скобками {} . Он захватывает значение между фигурными скобками и использует его для просмотра массива, где он должен соответствовать ключу. Затем он заменяет переменную фигурного скобки в строке значением в массиве соответствующего ключа.

Однако у него есть несколько проблем. Во-первых, когда я var_dump($matches) он помещает puts результаты в массив внутри массива. Поэтому я должен использовать два 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.' 

Я думаю, что для такой простой задачи вам не нужно использовать 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. 

Надеюсь, я не слишком поздно вступаю в партию – вот как я это сделаю:

 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 () в руководстве по PHP.)

Принимая во внимание характер языка PHP, я считаю, что этот подход должен обеспечить наилучшую производительность из всех перечисленных в этом потоке.

Я думаю, что вы можете значительно упростить свой код, с этим (если я неправильно интерпретирую некоторые из требований):

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

Это функция, которую я использую:

 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. 

Просто передайте ему текст для поиска и массив с заменами.

Просто голова для будущих людей, которые приземлятся на этой странице: все ответы (включая принятый ответ) с использованием петель foreach и / или метод str_replace восприимчивы к замене имени хорошего ol ' Johnny {STATUS} с 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.

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