Is it possible to access the same argument twice in sprintf?

6

In PHP time the function sprintf . With it we can format the values sequentially passed from the second parameter.

For example:

sprintf('Meu nome é %s e tenho %d anos de idade', 'Wallace', '26')

The output will be

  

My name is Wallace and I'm 26 years old.

But at some point I needed to have a functionality similar to what exists in languages like Python or C# , where you can repeat one of the arguments passed in the formatting string.

For example in Python

 s = "Meu nome eh {0}. Sim, o meu nome eh {0}. Eu tenho {1} anos de idade"
 s.format('Wallace', 1)

The output would be:

  

u "My name is Wallace, yes, my name is Wallace, I am 1 year old."

Note that the "Wallace" parameter was repeated without having to pass it twice.

Using sprintf of PHP, I need a similar solution. Is it possible to do the same operation of the example in Python in PHP , using the function sprintf ?

Note : I would like to know specifically about the sprintf function. In this case, user-created functions would not be welcome as a response.

    
asked by anonymous 08.07.2016 / 18:33

2 answers

11

According to the documentation for the sprintf function, you must use the $ character preceded by a number , which represents the number of the argument you want to capture, and preceded by the desired formatting flag (for example, s , f or d ).

The argument count starts from the number 1 . The expression must be initialized by % , like all other forms used to format an argument in the sprintf / printf

So, we could write the formatting string like this:

$tpl = 'Meu nome eh %1$s. Sim, o meu nome eh %1$s. Eu tenho %2$d anos de idade';

echo sprintf($tpl, 'Wallace', '26')

We read the code as follows:

%1$s "Replace this token with the first argument (Wallace) and format it as a string.

%2$d "Replace this token with the second argument (26) and format it to integer.

Functional sample

    
08.07.2016 / 18:46
2

The answer from @laerte is great and very correct, but I decided to leave two alternatives the answer just to make the most practical tokens handwriting, resembling str.format Python:

Suggestions 1:

I'll post the example @Gumbo made / posted this function:

function format() {
    $args = func_get_args();
    if (count($args) == 0) {
        return;
    }

    if (count($args) == 1) {
        return $args[0];
    }

    $str = array_shift($args);
    $str = preg_replace_callback('/\{(0|[1-9]\d*)\}/', create_function('$match', '$args = '.var_export($args, true).'; return isset($args[$match[1]]) ? $args[$match[1]] : $match[0];'), $str);
    return $str;
}

Usage:

$str = 'Meu nome eh {0}.
        Sim, o meu nome eh {0}.
        Eu tenho {1} anos de idade.
        {0} {1} {1} {0}';

echo format($str, 'Wallace', 26);

Suggestions 2:

This one I created now, is basically vsprintf merged with preg_replace

<?php
function format() {
    $args = func_get_args();
    if (empty($args)) {
        return null;
    }

    if (count($args) === 1) {
        return $args[0];
    }

    $str = array_shift($args);
    $str = preg_replace('#\{(\d+)\}#', '%$1\$s', $str);

    return vsprintf($str, $args);
}

Usage:

  

{0} is not supported, so it always starts from 1

$str = 'Meu nome eh {1}.
        Sim, o meu nome eh {1}.
        Eu tenho {2} anos de idade.
        {1} {2} {2} {1}';

echo format($str, 'Wallace', 26);

Example online: link

    
08.07.2016 / 19:31