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