带有命名参数的vsprintf或sprintf,或PHP中的简单模板解析

时间:2011-04-18 11:11:07

标签: php templates printf string.format named-parameters

我正在寻找一种方法,为sprintfprintf使用命名参数

示例:

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解决方案来实现这一目标,还是有另一种方式,也许是由PEAR提供的简单PHP模板,我可以通过坚持标准PHP实现这一目标?

感谢您的帮助。

10 个答案:

答案 0 :(得分:14)

我已经为这个需求编写了一个小组件。它被称为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"

希望可以提供帮助。

答案 1 :(得分:12)

据我所知,printf / sprintf不接受关联数组。

但是可以printf('%1$d %1$d', 1);

总比没有好;)

答案 2 :(得分:7)

晚了聚会,但是您可以简单地使用strtr来“翻译字符或替换子字符串”

<?php

$hours = 2;
$minutes = 24;
$seconds = 35;

echo strtr(
    'Last time logged in was %hours hours, %minutes minutes, %seconds seconds ago',
    [
        '%hours' => $hours,
        '%minutes' => $minutes,
        '%seconds' => $seconds
    ]
);

输出以下内容:

上次登录时间为2小时24分钟35秒前

答案 3 :(得分:5)

这是来自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"

答案 4 :(得分:5)

我知道这已经解决了太久了,但也许我的解决方案很简单,但对其他人有用。

使用这个小功能,您可以模仿简单的模板系统:

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>

也许不适合所有人和每一个案例,但它救了我。

答案 5 :(得分:3)

这就是我正在使用的:

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

答案 6 :(得分:2)

这真是去imho的最佳方式。没有神秘的人物,只需使用密钥名称!

取自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

答案 7 :(得分:1)

由于use关键字而导致5.3:

此功能支持格式化{{var}}或{{dict.key}},您可以将{{}}更改为{}等,以符合您的需求。

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岁,我有一只叫黄的猫。

答案 8 :(得分:-1)

足够简单

<?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']);

答案 9 :(得分:-1)

您将要避免在自定义函数中使用%,因为它会干扰其他实现,例如SQL中的日期格式,所以...

function replace(string $string, iterable $replacements): string
{
    return str_replace(
        array_map(
            function($k) {
                return sprintf("{%s}", $k);
            },
            array_keys($replacements)
        ),
        array_values($replacements),
        $string
    );      
}

$string1 = 'Mary had a little {0}. Its {1} was white as {2}.';

echo replace($string1, ['lamb', 'fleece', 'snow']);

$string2 = 'Mary had a little {animal}. Its {coat} was white as {color}.';

echo replace($string2, ['animal' => 'lamb', 'coat' => 'fleece', 'color' => 'snow']);

$ string1:玛丽有一只小羊羔。它的羊毛像雪一样洁白。
$ string2:玛丽有一只小羊羔。它的羊毛像雪一样洁白。