php sprintf()与外国字符?

时间:2013-04-14 19:42:39

标签: php utf-8 printf multibyte-functions

像sprintf一样的接缝有外来字符的问题吗?还是我做错了什么?看起来它在从字符串中移除像åäö这样的字符时起作用了。这有必要吗?

我希望为报告正确对齐以下行:

2011-11-27   A1823    -Ref. Leif  -           12 873,00    18.98
2011-11-30   A1856    -Rättat xx -            6 594,00    19.18

我正在使用这样的sprintf():% - 12s%-8s - % - 10s - %20s%8.2f

使用:php-5.3.23-nts-Win32-VC9-x86

4 个答案:

答案 0 :(得分:9)

PHP中的字符串基本上是字节数组(不是字符)。它们无法使用多字节编码(例如UTF-8)本地工作。

详情请见:
https://www.php.net/manual/en/language.types.string.php#language.types.string.details

PHP中的大多数字符串函数都具有多字节等效(使用mb_前缀)。但sprintf没有。

在php.net的函数文档页面上有一个用户评论(由“webmaster at cafe-clope dot net”)和sprintf的多字节实现。它可能对你有用:
https://www.php.net/manual/en/function.sprintf.php#55837

答案 1 :(得分:0)

如果您使用的字符符合ISO-8859-1字符集,则可以在格式化之前转换字符串,并在完成后将结果转换回UTF8。

utf8_encode(sprintf("%-12s %-8s", utf8_decode($paramOne), utf8_decode($paramTwo))

答案 2 :(得分:0)

我实际上是想找出php ^ 7是否最终具有本机mb_sprintf()等,但显然没有xD。

为了完整起见,这是我在某些旧项目中一直使用的简单解决方案。 只是将strlenmb_strlen之间的差异添加到所需的$targetLengh。 只是添加非多字节示例是为了便于比较=)。

$text = "Gultigkeitsprufung ist fehlgeschlagen: %{errors}";
$mbText = "Gültigkeitsprüfung ist fehlgeschlagen: %{errors}";
$mbTextRussian = "Проверка не удалась: %{errors}";

$targetLength = 60;
$mbTargetLength = strlen($mbText) - mb_strlen($mbText) + $targetLength;
$mbRussianTargetLength = strlen($mbTextRussian) - mb_strlen($mbTextRussian) + $targetLength;

printf("%{$targetLength}s\n", $text);
printf("%{$mbTargetLength}s\n", $mbText);
printf("%{$mbRussianTargetLength}s\n", $mbTextRussian);

结果

            Gultigkeitsprufung ist fehlgeschlagen: %{errors}
            Gültigkeitsprüfung ist fehlgeschlagen: %{errors}
                              Проверка не удалась: %{errors}

答案 3 :(得分:0)

问题

没有多字节格式函数。

想法

您不能转换输入字符串。您应该更改格式长度。 格式 %4s 表示 4 宽度(不是 字符 - 见脚注)。但是 PHP 格式函数计数字节。 因此,您应该将格式长度添加到 bytes - widths

实施

来自@nimmneun

function mb_sprintf($format, ...$args) {
    $params = $args;
    $callback = function ($length) use (&$params) {
        $value = array_shift($params);
        return $length[0] + strlen($value) - mb_strwidth($value);
    };
    $format = preg_replace_callback('/(?<=%|%-)\d+(?=s)/', $callback, $format);
    return sprintf($format, ...$args);
}

不要忘记另一个选项str_pad($input, $length, $pad_char=' ', STR_PAD_RIGHT)

function mb_str_pad(...$args) {
    $args[1] += strlen($args[0]) - mb_strwidth($args[0]);
    return str_pad(...$args);
}

脚注

亚洲字符有 3 个字节和 2 个宽度和 1 个字符长度。 如果您的格式是 %4s 并且输入的是一个亚洲字符,则您应该需要两个空格(填充)而不是三个。