44

I'm building a rather large Lucene.NET search expression. Is there a best practices way to do the string replacement in PHP? It doesn't have to be this way, but I'm hoping for something similar to the C# String.Format method.

Here's what the logic would look like in C#.

var filter = "content:{0} title:{0}^4.0 path.title:{0}^4.0 description:{0} ...";

filter = String.Format(filter, "Cheese");

Is there a PHP5 equivalent?

4
  • I think the indices of your string-placeholders must be incrementing, else it will throw an error. var filter = "content:{0} title:{1}^4.0 path.title:{2}^4.0 description:{3} ..."; Commented Aug 6, 2009 at 20:48
  • @BeowulfOF If my memory serves me well that wouldn't throw an error, just substitute every instance of {0} by "Cheese" (in the example). Commented Oct 27, 2013 at 12:10
  • See also: stackoverflow.com/questions/6229671 (comparison with python) Commented Aug 12, 2018 at 17:02
  • See also: stackoverflow.com/questions/7683133 (comparison with python) Commented Aug 12, 2018 at 17:06

5 Answers 5

70

You could use the sprintf function:

$filter = "content:%1$s title:%1$s^4.0 path.title:%1$s^4.0 description:%1$s ...";
$filter = sprintf($filter, "Cheese");

Or you write your own function to replace the {i} by the corresponding argument:

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;
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, Gumbo. Sprintf did the trick, although it seems to be 1-based rather than 0-based. In other words, %0$s didn't work but %1$s does. Thanks again.
create_function is deprecated in 7.2
7

Try sprintf http://php.net/sprintf

Comments

1

try this one if there is an error or 'create_function'

public static function format()
{
    $args = func_get_args();
    $format = array_shift($args);

    preg_match_all('/(?=\{)\{(\d+)\}(?!\})/', $format, $matches, PREG_OFFSET_CAPTURE);
    $offset = 0;
    foreach ($matches[1] as $data) {
        $i = $data[0];
        $format = substr_replace($format, @$args[$i], $offset + $data[1] - 1, 2 + strlen($i));
        $offset += strlen(@$args[$i]) - 2 - strlen($i);
    }

    return $format;
}

I found it from here

Comments

0

Using preg_replace_callback with a modern approach, we can even use a helper class library to support dot notation (adbario/php-dot-notation) inside out format along with array keys:

use \Adbar\Dot;

function format($text, ...$args)
{
    $params = new Dot([]);

    if (count($args) === 1 && is_array($args[0])) {
        $params->setArray($args[0]);
    } else {
        $params->setArray($args);
    }

    return preg_replace_callback(
        '/\{(.*?)\}/',
        function ($matches) use ($params) {
            return $params->get($matches[1], $matches[0]);
        },
        $text
    );
}

And we can use it like this:

> format("content:{0} title:{0}^4.0 path.title:{0}^4.0 description:{0} ...", "Cheese");
"content:Cheese title:Cheese^4.0 path.title:Cheese^4.0 description:Cheese ..."

> format(
    'My name is {name} and my age is {age} ({name}/{age})',
    ['name' => 'Christos', 'age' => 101]
);
"My name is Christos and my age is 101 (Christos/101)"

> format(
    'My name is {name}, my age is {info.age} and my ID is {personal.data.id} ({name}/{info.age}/{personal.data.id})',
    [
        'name' => 'Chris',
        'info' => [
            'age' => 40
        ],
        'personal' => [
            'data' => [
                'id' => '#id-1234'
            ]
        ]
    ]
);
"My name is Christos, my age is 101 and my ID is #id-1234 (Christos/101/#id-1234)"

Of course we can have a simple version without any extra libraries if we don't want multilevel array support using dot notation:

function format($text, ...$args)
{
    $params = [];

    if (count($args) === 1 && is_array($args[0])) {
        $params = $args[0];
    } else {
        $params = $args;
    }

    return preg_replace_callback(
        '/\{(.*?)\}/',
        function ($matches) use ($params) {
            if (isset($params[$matches[1]])) {
                return $params[$matches[1]];
            }
            return $matches[0];
        },
        $text
    );
}

Comments

0

I came up with this solution: https://github.com/andreasahlen/StringNetFormat

Very simple, because at first stage... feel free to use it.

print StringNetFormat("Hallo {0}, {1}, and {2}, ({0}, {1}, {2})", array ("Harry", "Doreen", "Wakka")); 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.