vsprintf или sprintf с именованными аргументами или простой синтаксический анализ шаблонов на PHP
Я ищу способ использовать именованные аргументы для sprintf
или printf
.
Пример:
sprintf(
'Last time logged in was %hours hours,
%minutes minutes, %seconds seconds ago'
,$hours,$minutes, $seconds
);
Или через vsprintf
и ассоциативный массив.
Я нашел здесь несколько примеров кодирования
function sprintfn ($format, array $args = array())
Http://php.net/manual/de/function.sprintf.php
И здесь
function vnsprintf( $format, array $data)
Http://php.net/manual/de/function.vsprintf.php
Где люди писали свои собственные решения.
Но мой вопрос в том, может ли быть стандартное решение PHP для достижения этого или есть другой способ, возможно, с помощью простого шаблона PHP, предоставленного PEAR, которого я могу достичь, придерживаясь стандартного PHP?
Спасибо за любую помощь.
9 answers
Насколько я знаю, printf/sprintf не принимает ассоциативные массивы.
Однако это можно сделать printf('%1$d %1$d', 1);
Лучше, чем ничего;)
Я написал небольшой компонент именно для этой цели. Он называется StringTemplate. С его помощью вы можете получить то, что хотите, с помощью такого кода:
$engine = new StringTemplate\Engine;
$engine->render(
'Last time logged in was {hours} hours, {minutes} minutes, {seconds} seconds ago',
[
'hours' => '08',
'minutes' => 23,
'seconds' => 12,
]
);
//Prints "Last time logged in was 08 hours, 23 minutes, 12 seconds ago"
Надеюсь, это может помочь.
Это из php.net
function vnsprintf( $format, array $data)
{
preg_match_all( '/ (?<!%) % ( (?: [[:alpha:]_-][[:alnum:]_-]* | ([-+])? [0-9]+ (?(2) (?:\.[0-9]+)? | \.[0-9]+ ) ) ) \$ [-+]? \'? .? -? [0-9]* (\.[0-9]+)? \w/x', $format, $match, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
$offset = 0;
$keys = array_keys($data);
foreach( $match as &$value )
{
if ( ( $key = array_search( $value[1][0], $keys, TRUE) ) !== FALSE || ( is_numeric( $value[1][0] ) && ( $key = array_search( (int)$value[1][0], $keys, TRUE) ) !== FALSE) )
{
$len = strlen( $value[1][0]);
$format = substr_replace( $format, 1 + $key, $offset + $value[1][1], $len);
$offset -= $len - strlen( 1 + $key);
}
}
return vsprintf( $format, $data);
}
Пример:
$example = array(
0 => 'first',
'second' => 'second',
'third',
4.2 => 'fourth',
'fifth',
-6.7 => 'sixth',
'seventh',
'eighth',
'9' => 'ninth',
'tenth' => 'tenth',
'-11.3' => 'eleventh',
'twelfth'
);
echo vnsprintf( '%1$s %2$s %3$s %4$s %5$s %6$s %7$s %8$s %9$s %10$s %11$s %12$s<br />', $example); // acts like vsprintf
echo vnsprintf( '%+0$s %second$s %+1$s %+4$s %+5$s %-6.5$s %+6$s %+7$s %+9$s %tenth$s %-11.3$s %+10$s<br />', $example);
Пример 2:
$examples = array(
2.8=>'positiveFloat', // key = 2 , 1st value
-3=>'negativeInteger', // key = -3 , 2nd value
'my_name'=>'someString' // key = my_name , 3rd value
);
echo vsprintf( "%%my_name\$s = '%my_name\$s'\n", $examples); // [unsupported]
echo vnsprintf( "%%my_name\$s = '%my_name\$s'\n", $examples); // output : "someString"
echo vsprintf( "%%2.5\$s = '%2.5\$s'\n", $examples); // [unsupported]
echo vnsprintf( "%%2.5\$s = '%2.5\$s'\n", $examples); // output : "positiveFloat"
echo vsprintf( "%%+2.5\$s = '%+2.5\$s'\n", $examples); // [unsupported]
echo vnsprintf( "%%+2.5\$s = '%+2.5\$s'\n", $examples); // output : "positiveFloat"
echo vsprintf( "%%-3.2\$s = '%-3.2\$s'\n", $examples); // [unsupported]
echo vnsprintf( "%%-3.2\$s = '%-3.2\$s'\n", $examples); // output : "negativeInteger"
echo vsprintf( "%%2\$s = '%2\$s'\n", $examples); // output : "negativeInteger"
echo vnsprintf( "%%2\$s = '%2\$s'\n", $examples); // output : [= vsprintf]
echo vsprintf( "%%+2\$s = '%+2\$s'\n", $examples); // [unsupported]
echo vnsprintf( "%%+2\$s = '%+2\$s'\n", $examples); // output : "positiveFloat"
echo vsprintf( "%%-3\$s = '%-3\$s'\n", $examples); // [unsupported]
echo vnsprintf( "%%-3\$s = '%-3\$s'\n", $examples); // output : "negativeInteger"
Я знаю, что это было решено слишком долго, но, возможно, мое решение достаточно простое, но полезное для кого-то другого.
С помощью этой небольшой функции вы можете имитировать простую систему шаблонов:
function parse_html($html, $args) {
foreach($args as $key => $val) $html = str_replace("#[$key]", $val, $html);
return $html;
}
Используйте его так:
$html = '<h1>Hello, #[name]</h1>';
$args = array('name' => 'John Appleseed';
echo parse_html($html,$args);
Это приведет к следующему результату:
<h1>Hello, John Appleseed</h1>
Может быть, не для всех и не для каждого случая, но это спасло меня.
Смотрите реализацию drupal
Https://api.drupal.org/api/drupal/includes%21bootstrap.inc/function/format_string/7
Это просто и не использует регулярное выражение
function format_string($string, array $args = array()) {
// Transform arguments before inserting them.
foreach ($args as $key => $value) {
switch ($key[0]) {
case '@':
// Escaped only.
$args[$key] = check_plain($value);
break;
case '%':
default:
// Escaped and placeholder.
$args[$key] = drupal_placeholder($value);
break;
case '!':
// Pass-through.
}
}
return strtr($string, $args);
}
function drupal_placeholder($text) {
return '<em class="placeholder">' . check_plain($text) . '</em>';
}
Пример:
$unformatted = 'Hello, @name';
$formatted = format_string($unformatted, array('@name' => 'John'));
Это действительно лучший способ пойти, имхо. Никаких загадочных символов, просто используйте имена ключей!
Как взято с сайта php: http://www.php.net/manual/en/function.vsprintf.php
function dsprintf() {
$data = func_get_args(); // get all the arguments
$string = array_shift($data); // the string is the first one
if (is_array(func_get_arg(1))) { // if the second one is an array, use that
$data = func_get_arg(1);
}
$used_keys = array();
// get the matches, and feed them to our function
$string = preg_replace('/\%\((.*?)\)(.)/e',
'dsprintfMatch(\'$1\',\'$2\',\$data,$used_keys)',$string);
$data = array_diff_key($data,$used_keys); // diff the data with the used_keys
return vsprintf($string,$data); // yeah!
}
function dsprintfMatch($m1,$m2,&$data,&$used_keys) {
if (isset($data[$m1])) { // if the key is there
$str = $data[$m1];
$used_keys[$m1] = $m1; // dont unset it, it can be used multiple times
return sprintf("%".$m2,$str); // sprintf the string, so %s, or %d works like it should
} else {
return "%".$m2; // else, return a regular %s, or %d or whatever is used
}
}
$str = <<<HITHERE
Hello, %(firstName)s, I know your favorite PDA is the %(pda)s. You must have bought %(amount)s
HITHERE;
$dataArray = array(
'pda' => 'Newton 2100',
'firstName' => 'Steve',
'amount' => '200'
);
echo dsprintf($str, $dataArray);
// Hello, Steve, I know your favorite PDA is the Newton 2100. You must have bought 200
Начиная с 5.3 из-за ключевого слова use
:
Эта функция поддерживает форматирование {{var}} или {{дикт.ключ}}, вы можете изменить {{}}
на {}
и т.д. в соответствии с вашими предпочтениями.
function formatString($str, $data) {
return preg_replace_callback('#{{(\w+?)(\.(\w+?))?}}#', function($m) use ($data){
return count($m) === 2 ? $data[$m[1]] : $data[$m[1]][$m[3]];
}, $str);
}
Пример:
$str = "This is {{name}}, I am {{age}} years old, I have a cat called {{pets.cat}}.";
$dict = [
'name' => 'Jim',
'age' => 20,
'pets' => ['cat' => 'huang', 'dog' => 'bai']
];
echo formatString($str, $dict);
Выход:
Это Джим, мне 20 лет, у меня есть кот по имени Хуан.
Вот что я использую:
$arr = ['a' => 'happy','b' => 'funny'];
$templ = "I m a [a] and [b] person";
$r = array_walk($arr,function($i,$k) use(&$templ){
$templ = str_replace("[$k]",$i,$templ);
} );
var_dump($templ);
Достаточно просто
<?php
//sprintf with place holders
function printPh($string,Array $params){
$tok = strtok($string,':');
$msg = '';
while($tok !== false){
$msg .= array_key_exists($tok,$params) ? $params[$tok] : $tok;
$tok = strtok(':');
}
return $msg;
}
echo spfwph('<p>:ph1: :ph2:</p>',['ph1'=>'placerholder 1','ph2'=>'placeholder 2']);