PHP中是否有C# String.Format()的等价函数?

44

我正在构建一个相当大的Lucene.NET搜索表达式。有没有PHP中最佳实践的方式进行字符串替换?它不一定要这样做,但我希望能够找到类似于C# String.Format方法的东西。

以下是C#中逻辑的样子。

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

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

有没有PHP5的等价物?


我认为你字符串占位符的索引必须递增,否则会抛出错误。 变量过滤器 = "内容:{0} 标题:{1} ^ 4.0 路径.标题:{2} ^ 4.0 描述:{3} ..." - Oliver Friedrich
如果我没记错的话,这不会抛出错误,只是将示例中的每个{0}替换为“Cheese”。 - Camilo Martin
参见:https://dev59.com/fG025IYBdhLWcg3wFxqa(与Python的比较) - dreftymac
参见:https://dev59.com/IWsz5IYBdhLWcg3wwKqh(与Python的比较) - dreftymac
5个回答

70

你可以使用sprintf函数

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

或者你可以编写自己的函数,将{i}替换为相应的参数:

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

谢谢,Gumbo。Sprintf解决了问题,尽管它似乎是基于1而不是基于0的。换句话说,%0$s没有起作用,但%1$s可以。再次感谢。 - Ben Griswold
2
create_function 在 7.2 版本中已被弃用。 - M.Parent

7

1

如果出现错误或者是 '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;
}

我从这里找到了它


0
我想出了这个解决方案:https://github.com/andreasahlen/StringNetFormat 非常简单,因为在第一阶段...随意使用它。
print StringNetFormat("Hallo {0}, {1}, and {2}, ({0}, {1}, {2})", array ("Harry", "Doreen", "Wakka")); 

0

使用现代方法的preg_replace_callback,我们甚至可以使用一个辅助类库来支持点符号表示法(adbario/php-dot-notation)以及数组键的内外格式:

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

我们可以像这样使用它:

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

当然,如果我们不需要使用点符号表示法支持多级数组,我们可以拥有一个简单版本而不需要任何额外的库:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接