Php sprintf() с иностранными символами? - программирование
Подтвердить что ты не робот

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

4b9b3361

Ответ 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 будет игнорироваться/оставаться неизменным.