Php sprintf() с иностранными символами?
Швы, похожие на 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-5.3.23-nts-Win32-VC9-x86
Ответы
Ответ 1
Строки в PHP в основном массивы байтов (не символов). Они не могут работать с многобайтовыми кодировками (такими как UTF-8).
Подробнее см.:
https://www.php.net/manual/en/language.types.string.php#language.types.string.details
Большинство строковых функций в PHP имеют многобайтовый эквивалент (с префиксом mb_
). Но sprintf
нет.
Там пользовательский комментарий ("webmaster at cafe-clope dot net") с многобайтовой реализацией sprintf
на странице документации по функции на php.net. Это может работать для вас:
https://www.php.net/manual/en/function.sprintf.php#55837
Ответ 2
Если вы используете символы, которые вписываются в набор символов ISO-8859-1, вы можете преобразовать строки перед форматированием и преобразовать результат обратно в UTF8, когда вы закончите
utf8_encode(sprintf("%-12s %-8s", utf8_decode($paramOne), utf8_decode($paramTwo))
Ответ 3
На самом деле я пытался выяснить, есть ли в 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) - 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}
обновление 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');
результат
thüs wörks ök
this works ok
Я только провел несколько удачных тестов пути, но он работает для PHP> = 5.6 и должен быть достаточно хорош, чтобы дать ppl представление о том, как инкапсулировать поведение. Однако он не работает с модификаторами повторения/порядка - например, %1$20s
будет игнорироваться/оставаться неизменным.