Заполнение строки до заданной длины PHP

Думал, форматный вывод строк с заполнением до заданной длины — это занятие для олдфагов, по какой-то причине до сих пор загружающих с дискетки MS DOS на компьютере менее мощном, чем современные электронные наручные часы.

Но в PHP-обработке массивов текста встретился с таким случаем, когда важно видеть все явные и не явные символы текста, да ещё чтобы текстовый массив выглядел приемлемо для понимания.

В общем случае для заполнения строки до заданной длины в PHP достаточно функции printf (sprintf).

Возможности функции для форматного вывода весьма впечатляют, но без бутылки шпаргалки сложно пользоваться функцией (это даже не минус, а просто мнение).

Например, выведем порядковый номер элемента какого-либо списка так, чтобы расстояние справа от него заполнилось пробелами до длины в 10 символов (минус длина номера):

printf( '%-10s', $i );

Не интуитивно, но эффективно. Интересует больше — гуглите. А меня эта функция не устроила тем, что неверно определяет длину строки в «utf-8» (наиболее популярная сейчас кодировка).

Например:

echo sprintf( "%'.-30s", 'шорт' ), "= короткий\n";
echo sprintf( "%'.-30s", 'лоооооооонг' ), "= длинный\n\n";

Ожидается такой результат:

шорт..........................= короткий
лоооооооонг...................= длинный

Но результат sprintf не столь прекрасен:

шорт......................= короткий
лоооооооонг........= длинный

Дело в том, что кириллические символы utf-8 в «понимании» обычных функций для работы со строками имеют такую длину, как 2 не-кириллических символа (например, знаки пунктуации и латинские символы). Отсюда и ошибки в подсчёте длины строк, и ещё артефакты при резке строк (в виде ромбиков с вопросиками), когда крайний символ режется на 2 части.

Для своих нужд я написал функцию для заполнения строки до заданной длины при выводе:

###
## Строка $t с заполнением справа строкой $s до длины $l
## минимальный размер $l = 3, иначе возвращается $t . $s
#
function fillstr_utf8( $t, $l, $s = '-  ' ) {
	# sprintf не корректно определяет длину строки в utf-8
	if ( $l < 3 ) return $t . $s;
	$len = mb_strlen( $t, 'utf-8' );
	if ( $len >= $l ) {
		$t = mb_substr( $t, 0, $l - 2, 'utf-8' ) .'…';
		$len = $l - 1;
	}
	$str = '';
	$k = $l - $len;
	if ( $k ) {
		while ( mb_strlen( $str, 'utf-8' ) <= $k ) $str .= $s;
		$t .= mb_substr( $str, -$k, $k, 'utf-8' );
	}
	return $t;
}

Эта функция не столь универсальна, как sprintf, зато результат выполнения

echo fillstr_utf8( 'шорт', 30, "." ), "= короткий\n";
echo fillstr_utf8( 'лоооооооонг', 30, "." ), "= длинный\n\n";

выглядит красиво:

шорт..........................= короткий
лоооооооонг...................= длинный

А можно даже так:

echo fillstr_utf8( 'шорт', 30, " -:- " ), "= короткий\n";
echo fillstr_utf8( 'лоооооооонг', 30, " -:- " ), "= длинный\n";
echo fillstr_utf8( 'очень длинный текст, который не поместится', 30, " -:- " ), "= overflow hidden\n\n";

/* Результат:

шорт  -:-  -:-  -:-  -:-  -:- = короткий
лоооооооонг-:-  -:-  -:-  -:- = длинный
очень длинный текст, который… = overflow hidden
*/

Гет юз!

Запись опубликована в рубрике Web-мастеринг с метками . Короткая ссылка для добавления в закладки: Заполнение строки до заданной длины PHP.

3 Responses

  1. Павлуха говорит:

    Удобная штука. Снова воспользовался описанным выше кодом. По крайней мере, мне самому оказался полезен этот пост. :)

  2. Дмитрий говорит:

    str_pad?

    • Павлуха говорит:

      Да, str_pad в этом случае лучше для примера, чем sprintf. Но, к сожалению, str_pad также не поддерживает мультибайтовые строки (например, кириллица в кодировке utf-8). Длину строки «абвгд» она определяет как 10 символов, а не как 5.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Иногда ваш комментарий может не отобразиться сразу после публикации - будто пропал. Не волнуйтесь, он не пропадёт и появится потом, после моего одобрения.