php sprintf()是否包含外来字符?

php sprintf()是否包含外来字符?,php,utf-8,printf,multibyte-functions,Php,Utf 8,Printf,Multibyte Functions,像sprintf一样的接缝对foregin角色有问题吗?还是我做错了什么?不过,当从字符串中移除像åäö这样的字符时,它看起来很有效。有必要吗 我希望报告的以下行正确对齐: 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-%20

像sprintf一样的接缝对foregin角色有问题吗?还是我做错了什么?不过,当从字符串中移除像åäö这样的字符时,它看起来很有效。有必要吗

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

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中的php-5.3.23-nts-Win32-VC9-x86

字符串基本上是字节数组(而不是字符)。它们不能在本地使用多字节编码(如UTF-8)

有关详细信息,请参见:

PHP中的大多数字符串函数都有多字节等价项(前缀为
mb
)。但是
sprintf
没有

在php.net的函数文档页面上有一条用户评论(由“viktor at textalk.com”撰写),其中包含了sprintf的多字节实现。它可能适合您:

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

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

我实际上是想知道PHP^7是否最终有了一个本机的
mb_sprintf()
,但显然没有xD

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

$text=“Gultigkeitsprufung ist fehlgeschlagen:%{errors}”;
$mbText=“Gültigkeitsprüfung ist fehlgeschlagen:%{errors}”;
$mbTextRussian=“ППаааааааа:%{errors}”;
$targetLength=60;
$mbTargetLength=strlen($mbText)-MBSTRLEN($mbText)+$targetLength;
$mbRussianTargetLength=strlen($mbtext俄语)-mb_strlen($mbtext俄语)+$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}
thüs       wörks              ök
this       works              ok

更新2019-06-12


@flowtron让我再考虑一下。一个简单的
mb_sprintf()
可能是这样的

function mb_sprintf($format, ...$args) {
    $params = $args;

    $callback = function ($length) use (&$params) {
        $value = array_shift($params);
        return strlen($value) - mb_strlen($value) + $length[0];
    };

    $format = preg_replace_callback('/(?<=%|%-)\d+(?=s)/', $callback, $format);

    return sprintf($format, ...$args);
}

echo mb_sprintf("%-10s %-10s %10s\n", 'thüs', 'wörks', 'ök');
echo mb_sprintf("%-10s %-10s %10s\n", 'this', 'works', 'ok');
我在这里只做了一些愉快的路径测试,但它适用于PHP>=5.6,应该足以让ppl了解如何封装行为。 但它不适用于重复/顺序修饰符-例如,
%1$20s
将被忽略/保持不变。

问题 没有多字节格式函数

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

启动位置 来自@nimmnen

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);
}
脚注 亚洲字符有3个字节、2个宽度和1个字符长度。
如果格式为
%4s
且输入为一个亚洲字符,则需要两个空格(填充)而不是三个。

此问题(不同的字符由不同的字节数组成,不同的图形集由不同的字符数组成)与有些类似(但与不同)。底线是,将数据放在HTML表中可能是最容易的。是的,这绝对不是一个重复的问题,这个问题是关于多字节字符是sprintf(),另一个是关于字体显示宽度。这根本不是一个重复的问题。。。你可以这样做:utf8_编码(sprintf('format',utf8_解码($yourstring));…当然,如果给出了许多参数,您必须检查每个参数。这个问题是关于unicode代码点大于127的字符,当使用UTF-8编码时,它使用多个字节。不幸的是
sprintf
printf
不能处理这个问题。当打印使用UTF-8编码时使用6字节的2个字符字符串时,
%8s
打印错误的空格数(8-6=2),而不是(8-2=6)。这与使用的字体无关,就像这个问题应该重复的问题。这个问题是关于phps缺乏对多字节字符的支持。正确的解释,但链接函数对我不起作用–即使在完成备注中提到的mb_*函数名替换之后。我希望比@nimmnen提供的更好的解决方案,这也是我目前的黑客解决方案。我本来希望找到一些不那么黑客的解决方案,因为这是我一直在做的方式——因为@Martin Prikryl中的链接例程(对我来说)不起作用。你让我再给它一次=)
function mb_str_pad(...$args) {
    $args[1] += strlen($args[0]) - mb_strwidth($args[0]);
    return str_pad(...$args);
}