2011-04-18 9 views
8

Estoy buscando una forma de utilizar con los argumentos nombrados para sprintf o printf.vsprintf o sprintf con argumentos con nombre, o simple análisis de plantillas en PHP

Ejemplo:

sprintf(
    'Last time logged in was %hours hours, 
    %minutes minutes, %seconds seconds ago' 
    ,$hours,$minutes, $seconds 
); 

o vía vsprintf y una matriz asociativa.

He encontrado algunos ejemplos de codificación aquí

function sprintfn ($format, array $args = array()) 

http://php.net/manual/de/function.sprintf.php

y aquí

function vnsprintf($format, array $data) 

http://php.net/manual/de/function.vsprintf.php

donde la gente escribía sus propias soluciones.

Pero mi pregunta es, ¿existe tal vez una solución PHP estándar para lograr esto o hay otra manera, tal vez con una simple plantilla PHP proporcionada por PEAR, que puedo lograr esto apegándome al PHP estándar?

Gracias por cualquier ayuda.

+0

** seealso: ** https://stackoverflow.com/questions/13325698/php-sprintf-with-array – dreftymac

Respuesta

9

Que yo sepa, printf/sprintf no acepta matrices asociadas.

Sin embargo, es posible hacer printf('%1$d %1$d', 1);

mejor que nada;)

+0

gracias por su comentario, he visto esto por supuesto. Pero pregunto si hay otras formas de lograr esto –

+1

str_replace/preg_replace/strtr, pero dudo que sea lo que estás buscando. También puede aprovechar la sintaxis de HEREDOC (http://php.net/heredoc) –

+1

Fui con las soluciones de php.net, sin embargo, gracias por responder –

5

Esto es de 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); 
} 

Ejemplo:

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

Ejemplo 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" 
3

Esta es realmente la mejor manera de hacerlo. ¡No hay personajes crípticos, solo usa los nombres de las teclas!

, tomado del sitio de 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 
+3

Ciertamente simple, pero usando el modificador PCRE '/ e' es ahora [obsoleto] (http://php.net/manual/en/reference.pcre.pattern.modifiers.php) y una mala idea en primer lugar. – Synchro

11

He escrito un pequeño componente precisamente por esta necesidad. Se llama StringTemplate. Con él se puede conseguir lo que quiera con un código como este:

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

esperanza que puede ayudar.

+0

¡Me encanta este componente! – Ema4rl

5

Sé que esto se ha resuelto por mucho tiempo, pero tal vez mi solución es lo suficientemente simple, pero útil para otra persona.

Con esta pequeña función puede imitar un sencillo sistema de plantillas:

function parse_html($html, $args) { 

    foreach($args as $key => $val) $html = str_replace("#[$key]", $val, $html); 

    return $html; 
} 

utilizar de esta manera:

$html = '<h1>Hello, #[name]</h1>'; 
$args = array('name' => 'John Appleseed'; 

echo parse_html($html,$args); 

Esto seria:

<h1>Hello, John Appleseed</h1> 

Tal vez no para todos y cada caso, pero me salvó.

+0

¡Ese es un buen enfoque! ... Funciona como encanto: D solo usa una gran cantidad de recursos cuando miras tus registros (pasé muchos argumentos), si hubiera una forma de que printf o sprintf aceptaran array asociativo ... habría sido Aweeesome, Nice Job BTW – Fahad

+0

@Fahad El ciclo requiere 'str_replace'-ing para * cada * tecla, que siempre comenzará a escanear desde el principio de la cadena cada vez, lo cual es una gran pérdida de tiempo. Una mejor variación construiría una cadena completamente nueva basada en la entrada, iterando sobre la cadena fuente solo una vez. – Deji

4

Véase aplicación de Drupal

https://api.drupal.org/api/drupal/includes%21bootstrap.inc/function/format_string/7

Es muy sencillo y no utiliza expresiones regulares

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>'; 
} 

Ejemplo:

$unformatted = 'Hello, @name'; 
$formatted = format_string($unformatted, array('@name' => 'John')); 
0

lo suficientemente simple

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

Desde 5.3 a causa de la palabra clave use:

Esta función es compatible con el formato {{var}} o {{}} dict.key, se puede cambiar el {{}} a {} etc para que coincida con usted a favor.

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

Ejemplo:

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

Salida:

Este es Jim, tengo 20 años, tengo un gato llamado Huang.

Cuestiones relacionadas