Как разбить строку на символы php
Перейти к содержимому

Как разбить строку на символы php

str_split

Если указан необязательный аргумент length , возвращаемый массив будет содержать части исходной строки длиной length каждая, иначе каждый элемент будет содержать один символ.

Если length меньше 1, возвращается false . Если length больше длины строки string , то вся строка будет возвращена в первом и единственном элементе массива.

Примеры

Пример #1 Пример использования str_split()

$str = «Hello Friend» ;

$arr1 = str_split ( $str );
$arr2 = str_split ( $str , 3 );

print_r ( $arr1 );
print_r ( $arr2 );

Результат выполнения данного примера:

Примечания

Замечание:

Функция str_split() производит разбивку по байтам, а не по символам, в случае использования строк в многобайтных кодировках. Используйте функцию mb_str_split() , чтобы разбить строку на кодовые точки.

Смотрите также

  • mb_str_split() — Если задана многобайтовая строка возвращает массив символов
  • chunk_split() — Разбивает строку на фрагменты
  • preg_split() — Разбивает строку по регулярному выражению
  • explode() — Разбивает строку с помощью разделителя
  • count_chars() — Возвращает информацию о символах, входящих в строку
  • str_word_count() — Возвращает информацию о словах, входящих в строку

User Contributed Notes 40 notes

A proper unicode string split;

<?php
function str_split_unicode ( $str , $l = 0 ) <
if ( $l > 0 ) <
$ret = array();
$len = mb_strlen ( $str , «UTF-8» );
for ( $i = 0 ; $i < $len ; $i += $l ) <
$ret [] = mb_substr ( $str , $i , $l , «UTF-8» );
>
return $ret ;
>
return preg_split ( «//u» , $str , — 1 , PREG_SPLIT_NO_EMPTY );
>
?>

$s = «Ilık süt»; // Mild milk

print_r(str_split($s, 3));
print_r(str_split_unicode($s, 3));

A new version of «str_split_unicode» prev.

<?php
function str_split_unicode ( $str , $length = 1 ) <
$tmp = preg_split ( ‘

u’ , $str , — 1 , PREG_SPLIT_NO_EMPTY );
if ( $length > 1 ) <
$chunks = array_chunk ( $tmp , $length );
foreach ( $chunks as $i => $chunk ) <
$chunks [ $i ] = join ( » , (array) $chunk );
>
$tmp = $chunks ;
>
return $tmp ;
>
?>

$s = ‘Özgür Yazılım!’; // Open Source!

Version of str_split by rlpvandenberg at hotmail dot com is god-damn inefficient and when $i+$j > strlen($text) [last part of string] throws a lot of notice errors. This should work better:

if(! function_exists(‘str_split’))
<
function str_split($text, $split = 1)
<
$array = array();

for ($i = 0; $i < strlen($text);)
<
$array[] = substr($text, $i, $split);
$i += $split;
>

For those it may concern:

We encountered trubble when trying to str_split a UTF-8 encoded string, containing such Swedish letters as å, å and ö.

It seems that this function splits according to byte-length and not character length. So if the letter «Å» takes 2 bytes, then str_split() will only return the first bite of the character «Å».

We ain’t 100% sure that this is the case but this was anyhow the result we got. So we used the multi-byte functions instead.

I noticed in the post below me that his function would return an array with an empty key at the end.

So here is just a little fix for it.

//Create a string split function for pre PHP5 versions
function str_split ( $str , $nr ) <

//Return an array with 1 less item then the one we have
return array_slice ( split ( «-l-» , chunk_split ( $str , $nr , ‘-l-‘ )), 0 , — 1 );

i use this in PHP4

function str_split($str) <
return preg_split(‘//’,$str);
>

The documentation fails to mention what happens when the string length does not divide evenly with the chunk size. Not sure if the same behavior for all versions of PHP so I offer the following code to determine this for your installation. On mine [version 5.2.17], the last chunk is an array the length of the remaining chars.

$da_string = «When number of chars does’t divide evenly» ;
$len = strlen ( $da_string );
$chunk_size = 8 ;
echo «<p> Length of <span style=’font-family:monospace’> $da_string </span>: $len </p>\n» ;
echo «<p> Chunck size: $chunk_size </p>\n» ;
$parts = str_split ( $da_string , $chunk_size );
$html = «<table border=’5′ cellpadding=’3′ cellspacing=’4′>\n» ;
foreach ( $parts as $idx => $part )
<
$html .= «<tr>\n» ;
$html .= «<td style=’font-family:monospace’> $part </td>» ;
$chars = str_split ( $part );
foreach ( $chars as $char )
<
if ( $char === ‘ ‘ )
<
$html .= «<td>&nbsp;</td>» ;
>
else
<
$html .= «<td> $char </td>» ;
>
>
$html .= «</tr>\n» ;
>
$html .= «</table>\n» ;
echo $html ;
?>

The manual don’t says what is returned when you parse a different type of variable.

This is the example:

$str1 = «Long» ; // More than 1 char
$str2 = «x» ; // Only 1 char
$str3 = «» ; // Empty String
$str4 = 34 ; // Integer
$str5 = 3.4 ; // Float
$str6 = true ; // Bool
$str7 = null ; // Null

$spl1 = str_split ( $str1 );
$spl2 = str_split ( $str2 );
$spl3 = str_split ( $str3 );
$spl4 = str_split ( $str4 );
$spl5 = str_split ( $str5 );
$spl6 = str_split ( $str6 );
$spl7 = str_split ( $str7 );

echo count ( $spl1 ); // 4
echo count ( $spl2 ); // 1
echo count ( $spl3 ); // 1
echo count ( $spl4 ); // 2
echo count ( $spl5 ); // 3
echo count ( $spl6 ); // 1
echo count ( $spl7 ); // 1

print_r ( $spl1 );
print_r ( $spl2 );
print_r ( $spl3 );
print_r ( $spl4 );
print_r ( $spl5 );
print_r ( $spl6 );
print_r ( $spl7 );

revised function from tatsudoshi

Fixed some bugs, more php5 style compliant
<?php
if(! function_exists ( ‘str_split’ )) <
function str_split ( $string , $string_length = 1 ) <
if( strlen ( $string )> $string_length || ! $string_length ) <
do <
$c = strlen ( $string );
$parts [] = substr ( $string , 0 , $string_length );
$string = substr ( $string , $string_length );
> while( $string !== false );
> else <
$parts = array( $string );
>
return $parts ;
>
>
?>

It’s mentioned in the Return Values section above («If the split_length length exceeds the length of string, the entire string is returned as the first (and only) array element»), but note that an input of empty string will return array(1) < [0]=> string(0) "" >. Interestingly an input of NULL will also return array(1) < [0]=> string(0) "" >.

Compare this with, say, <?php preg_split ( ‘//’ , $inputString , — 1 , PREG_SPLIT_NO_EMPTY ); ?> which will return array(0) < >for an input of empty string or NULL. I find this to be a bit more intuitive.

Hope this helps.

The previous suggestion is almost correct (and will only working for strlen=1. The working PHP4 function is:

<code>
function str_split($text, $split = 1) <
//place each character of the string into and array
$array = array();
for ($i=0; $i < strlen($text); $i++) <
$key = «»;
for ($j = 0; $j < $split; $j++) <
$key .= $text[$i+$j];
>
$i = $i + $j — 1;
array_push($array, $key);
>
return $array;
>
</code>

here an equivalent function for unicode string :

<?php
function uni_strsplit ( $string , $split_length = 1 )
<
preg_match_all ( ‘`.`u’ , $string , $arr );
$arr = array_chunk ( $arr [ 0 ], $split_length );
$arr = array_map ( ‘implode’ , $arr );
return $arr ;
>

heres my version for php4 and below

function str_split_php4 ( $text , $split = 1 )
<
if (! is_string ( $text )) return false ;
if (! is_numeric ( $split ) && $split < 1 ) return false ;

$len = strlen ( $text );

while ( $i < $len )
<
$key = NULL ;

for ( $j = 0 ; $j < $split ; $j += 1 )
<
$key .= $text < $i >;

I needed a function that could split a string from the end with any left over chunk being at the beginning of the array (the beginning of the string).

<?php
function str_rsplit ( $str , $sz )
<
// splits a string «starting» at the end, so any left over (small chunk) is at the beginning of the array.
if ( ! $sz ) < return false ; >
if ( $sz > 0 ) < return str_split ( $str , $sz ); >// normal split

$l = strlen ( $str );
$sz = min (- $sz , $l );
$mod = $l % $sz ;

// split
return array_merge (array( substr ( $str , 0 , $mod )), str_split ( substr ( $str , $mod ), $sz ));
>

$str = ‘aAbBcCdDeEfFg’ ;
str_split ( $str , 5 ); // return: <'aAbBc','CdDeE','fFg'>
str_rsplit ( $str , 5 ); // return: <'aAbBc','CdDeE','fFg'>
str_rsplit ( $str ,- 5 ); // return:

Even shorter version:

//place each character (or group of) of the
string into and array

function str_split_php4($sText, $iSplit = 1)
<
$iSplit=(integer) $iSplit; // sanity check
if ($iSplit < 1) < return false; >
$aResult = array();
for($i=0, $limit=strlen($sText); $i < $limit; $i+=$iSplit) <
$aResult[]=substr($sText, $i, $iSplit);
>
return $aResult;
>

the fastast way (that fits my needs) to replace str_split() in php 4 i found is this:

<?php
if(! function_exists ( ‘str_split’ )) <
function str_split ( $string , $split_length = 1 ) <
$array = explode ( «\r\n» , chunk_split ( $string , $split_length ));
array_pop ( $array );
return $array ;
>
>
?>

i also tested the provided functions in the comments..

(the differences are 0.001 to 0.00001 sec)

this function can perform a reverse str_split. I write it for PHP4 but you can rename It for other versions..

if ( !function_exists(‘str_split’) ) <
function str_split($string,$split_length=1) <
$sign = (($split_length<0)?-1:1);
$strlen = strlen($string);
$split_length = abs($split_length);
if ( ($split_length==0) || ($strlen==0) ) <
$result = false;
//$result[] = «»;
>
elseif ($split_length >= $strlen) <
$result[] = $string;
>
else <
$length = $split_length;
for ($i=0; $i<$strlen; $i++) <
$i=(($sign<0)?$i+$length:$i);
$result[] = substr($string,$sign*$i,$length);
$i—;
$i=(($sign<0)?$i:$i+$length);
if ( ($i+$split_length) > ($strlen) ) <
$length = $strlen-($i+1);
>
else <
$length = $split_length;
>
>
>
return $result;
>
>

Note that in atleast in PHP 5.5.9 (Zend Engine v2.5.0), str_split with an integer value as an argument may return unpredictable results.

If your number contains leading 0’s, the result array is unprdictable as it may contain any number of digits from the argument or (mostly) just a 0.

Here are a list of possible values that might be returned:
-Interger

<?php
print_r ( str_split (0080450)); // does not work
print_r ( str_split ( strval (0080450))); // neither this

/*
* Outputs:
* Array
* (
* [0] => 0
* )
*/
?>

BUT
<?php
print_r ( str_split ( 80450 )); // works fine
print_r ( str_split ( strval ( 80450 ))); // so does this

/*
* Outputs:
* (
* [0] => 8
* [1] => 0
* [2] => 4
* [3] => 5
* [4] => 0
* )
*/
?>

Floating point numbers have their leading and trailing 0s cut off:
<?php
print_r ( str_split ( 0080450.0010 )); // works but.. print_r(str_split(strval(0080450.0010))); // same here..

/*
Outputs:
* Array
* (
* [0] => 8
* [1] => 0
* [2] => 4
* [3] => 5
* [4] => 0
* [5] => .
* [6] => 0
* [7] => 0
* [8] => 1
* )
*/
?>

I’m not sure if this can be considered a bug, since this is due to how type conversion and casting works, so i just posted it here.
I’ve notced that this is how strval() works. Can anyone shed light into this.

Here is a better version of queremy@gmail.com’s solution. It has the exact same interface as str_split, but works with any UTF-8 string.

<?php
if (! function_exists ( ‘mb_str_split’ )) <
/**
* Converts an UTF-8 string to an array.
*
* E.g. mb_str_split(«Hello Friend»);
* returns [‘H’, ‘e’, ‘l’, ‘l’, ‘o’, ‘ ‘, ‘w’, ‘o’, ‘r’, ‘l’, ‘d’]
*
* @param string $string The input string.
* @param int $split_length Maximum length of the chunk. If specified, the returned array will be broken down
* into chunks with each being split_length in length, otherwise each chunk will be one character in length.
* @return array|boolean
* —
* — If the split_length length exceeds the length of string, the entire string is returned
* as the first (and only) array element.
* — False is returned if split_length is less than 1.
*/
function mb_str_split ( $string , $split_length = 1 )
<
if ( $split_length == 1 ) <
return preg_split ( «//u» , $string , — 1 , PREG_SPLIT_NO_EMPTY );
> elseif ( $split_length > 1 ) <
$return_value = [];
$string_length = mb_strlen ( $string , «UTF-8» );
for ( $i = 0 ; $i < $string_length ; $i += $split_length ) <
$return_value [] = mb_substr ( $string , $i , $split_length , «UTF-8» );
>
return $return_value ;
> else <
return false ;
>
>
>
?>

For those who work with PHP < 5:

if (! function_exists ( «str_split» )) <
function str_split ( $string , $length = 1 ) <
if ( $length <= 0 ) <
trigger_error ( __FUNCTION__ . «(): The the length of each segment must be greater then zero:» , E_USER_WARNING );
return false ;
>
$splitted = array();
$str_length = strlen ( $string );
$i = 0 ;
if ( $length == 1 ) <
while ( $str_length —) <
$splitted [ $i ] = $string [ $i ++];
>
> else <
$j = $i ;
while ( $str_length > 0 ) <
$splitted [ $j ++] = substr ( $string , $i , $length );
$str_length -= $length ;
$i += $length ;
>
>
return $splitted ;
>
>

A good way to use this method to convert CamelCase text into nice text would be-

<?php
/**
Returns a formatted string based on camel case.
e.g. «CamelCase» -> «Camel Case».
*/
function FormatCamelCase ( $string ) <
$output = «» ;
foreach( str_split ( $string ) as $char ) <
strtoupper ( $char ) == $char and $output and $output .= » » ;
$output .= $char ;
>
return $output ;
>
?>

how I can conwert
$string
‘1, 2, 5, 6, 10, 13, 23’
from ENUM at mySQL to

<?php
function enum_to_array ( $psEnum )
<
$aReturn = array();
$aTemp = explode ( ‘, ‘ , $psEnum );
for ( $i = $aTemp [ 0 ]; $i <= $aTemp [ count ( $aTemp )- 1 ]; $i ++)
<
$aReturn [ $i ] = in_array ( $i , $aTemp );
>
>
?>

I was looking for a function that would split a string into an array like str_split() and found Razor’s function above. Just though that I would simplify the code a little.

<?php
function str_split_php4 ( $text , $split = 1 ) <
//place each character of the string into and array
$array = array();
for( $i = 0 ; $i < strlen ( $text ); $i ++) <
$key = NULL ;
for ( $j = 0 ; $j < $split ; $j ++) <
$key .= $text [ $i ];
>
array_push ( $array , $key );
>
return $array ;
>
?>

Both mine and worksRazor’s work well, I just prefer to use less code. I could have written one myself, but I was just being lazy.

Here is what I use. I started with examples here but modified to my own version:

function str_split ( $text , $split = 1 )
<
if (! is_string ( $text )) return false ;
if (! is_numeric ( $split ) && $split < 1 ) return false ;
$len = strlen ( $text );
$array = array();
$s = 0 ;
$e = $split ;
while ( $s < $len )
<
$e =( $e < $len )? $e : $len ;
$array [] = substr ( $text , $s , $e );
$s = $s + $e ;
>
return $array ;
>
>
?>

If you use PHP 4 and don’t need the split_length parameter, here’s the shortest replacement:

If you pass 0 as the second argument, then an error occurs

ValueError : str_split(): Argument #2 ($length) must be greater than 0

<?
//fast & short version od str_split

function string_split($str)
<
$str_array=array();
$len=strlen($str);
for($i=0;$i<$len;$i++) $str_array[]=$str<$i>;
return $str_array;
>
//example :
var_dump (string_split(«split this»));
?>

I think that the last post by carlosreche at yahoo dot com is too complicated.
It’s much easier if you do it like this:

<?php
if (! function_exists ( «str_split» )) <
function str_split ( $str , $length = 1 ) <
if ( $length < 1 ) return false ;
$strlen = strlen ( $str );
$ret = array();
for ( $i = 0 ; $i < $strlen ; $i += $length ) <
$ret [] = substr ( $str , $i , $length );
>
return $ret ;
>
>
?>

I hope it helps for those with PHP <5

The very handy str_split() was introduced in PHP 5, but a lot of us are still forced to use PHP 4 at our host servers. And I am sure a lot of beginners have looked or are looking for a function to accomplish what str_split() does.

Taking advantge of the fact that strings are ‘arrays’ I wrote this tiny but useful e-mail cloaker in PHP, which guarantees functionality even if JavaScript is disabled in the client’s browser. Watch how I make up for the lack of str_split() in PHP 4.3.10.

// cloackEmail() accepts a string, the email address to be cloaked
function cloakEmail ( $email ) <

// We create a new array called $arChars, which will contain the individula characters making up the email address. The array is blank for now.
$arChars = array();

// We extract each character from the email ‘exploiting’ the fact that strings behave like an array: watch the ‘$email[$i]’ bit, and beging to fill up the blank array $arChars
for ( $i = 0 ; $i < strlen ( $email ); $i ++)

// Now we work on the $arChars array: extract each character in the array and print out it’s ASCII value prefixed with ‘&#’ to convert it into an HTML entity
foreach ( $arChars as $char )

// The result is an email address in HTML entities which, I hope most email address harvesters can’t read.

preg_split

Если указан, функция возвращает не более, чем limit подстрок, оставшаяся часть строки будет возвращена в последней подстроке. Специальное значение limit , равное -1, 0 или NULL подразумевает отсутствие ограничения, и, в качестве фактического стандарта в PHP, можно использовать NULL для пропуска параметра flags .

flags может быть любой комбинацией следующих флагов (объединенных с помощью побитового оператора |): PREG_SPLIT_NO_EMPTY Если указан этот флаг, функция preg_split() вернет только непустые подстроки. PREG_SPLIT_DELIM_CAPTURE Если указан этот флаг, выражение, заключенное в круглые скобки в разделяющем шаблоне, также извлекается из заданной строки и возвращается функцией. PREG_SPLIT_OFFSET_CAPTURE

Если указан этот флаг, для каждой найденной подстроки будет указана ее позиция в исходной строке. Необходимо помнить, что этот флаг меняет формат возвращаемого массива: каждый элемент будет содержать массив, содержащий в индексе с номером 0 найденную подстроку, а смещение этой подстроки в параметре subject — в индексе 1.

Возвращаемые значения

Возвращает массив, состоящий из подстрок заданной строки subject , которая разбита по границам, соответствующим шаблону pattern .

Примеры

Пример #1 preg_split() пример: Получение подстрок из заданного текста

Результат выполнения данного примера:

Пример #2 Разбиваем строку на составляющие символы

Результат выполнения данного примера:

Пример #3 Разбиваем строку с указанием смещения для каждой из найденных подстрок

Результат выполнения данного примера:

Примечания

Если вам не нужна мощь регулярных выражений, вы можете выбрать более быстрые (хоть и простые) альтернативы наподобие explode() или str_split() .

Если соответствий не нашлось, то возвращается массив с единственным элементом равным всей строке.

Как разбить строку на символы php

Copy raw contents

Функции работы с UTF-8 строками в PHP

Краткое содержание: используйте mb_* функции. Не используйте доступ к строке по индексу ( $str[0] ). В регулярных выражениях используйте флаг u (он говорит, что используется utf-8, а не однобайтовая кодировка).

Некоторые функции PHP (вроде strlen , substr , а также обращение к строке как к массиву: $str[0] ) не работают с текстами в многобайтовых кодировках (вроде utf-8). Такие функции нормально работают со строкой из латинских букв, но если мы попытаемся передать строку с кирилицей, то буквы превращаются в непонятные символы или теряются.

Вот пример неправильно написанного кода:

Чтобы понять, почему так происходит, придется вспомнить историю. В компьютерах данные в памяти хранятся в виде байтов, где байт можно представить целым числом от 0 до 255. Соответственно, текст тоже хранится в памяти в виде последовательности байтов. Первоначально для этого использовались однобайтовые кодировки вроде ASCII, в которых символы кодировались числами от 0 до 255, и таким образом один символ занимал в памяти ровно один байт. Написанный в то время код опирался на это предположение. Например, функция для определения длины строки просто смотрела, сколько байтов памяти она занимает и возвращала это число, не глядя на содержимое этих байтов.

К примеру, строка «hello» кодируется в ASCII как последовательность из 5 байтов 104 , 101 , 108 , 108 , 111 .

Когда компьютеры стали распространяться по всему миру, 256 кодов стало недостаточно, чтобы представить десятки тысяч символов из различных языков и в 90-е годы пришлось переходить на Юникод (кодировка, которая пытается присвоить коды всем существующим символам из любых языков) и многобайтовые кодировки вроде utf-8. В utf-8 символ может кодироваться последовательностью длиной от 1 до 4 байтов. Латинские символы в utf-8 кодируются одним байтом с точно таким же кодом, как и в ASCII, а символы кириллицы — двумя.

Вот как кодируется в utf-8 слово «азъ»: 208 , 176 , 208 , 183 , 209 , 138 . Подробно про кодировки и их историю я написал в отдельной статье про способ кодирования строк в памяти.

Старый код, рассчитанный на однобайтовые кодировки, не работает с utf-8. Например, функция определения длины строки, которая просто считает число байт в ней, вернет 6 вместо 3 для строки «азъ». Функция, которая отрезает первый символ строки, вернет один байт 208 вместо пары байт 208 , 176 , которые представляют букву «а». Функция, которая переворачивает строку, перепутает байты местами.

В PHP, к сожалению, функции вроде strlen используют такой устаревший код, и потому дают некорретные результаты. Вместо них надо использовать функции, которые «знают» о многобайтовых кодировках и корректно обрабатывают тексты в них. В PHP такие функции содержатся в расширении mbstring и имеют имена, начинающиеся с mb_, например, mb_strlen , mb_substr .

Для корректной работы этих функций надо сообщить им о том, какая кодировка используется. Это делается либо опцией default_charset в файле php.ini, либо функцией mb_internal_encoding в начале программы:

В большинстве случаев utf-8 уже задана как кодировка по умолчанию, и делать ничего не требуется, но описанные выше советы позволяют гарантировать, что кодировка задана правильно.

К сожалению, некоторые учебники или статьи могут до сих пор использовать давно устаревшие функции. Вот таблица, показывающая, какие функции стоит использовать вместо них:

Не поддерживает utf-8 Поддерживает utf-8 Примечания
Взятие символа по индексу: $str[0] mb_substr($str, 0, 1)
chr mb_chr
lcfirst нету аналога Можно отрезать первую букву с помощью mb_substr(), перевести ее в нижний регистр mb_strtolower() и приклеить остаток строки
ord mb_ord ord() возвращает значение первого байта в строке от 0 до 255, а mb_ord() — код первого символа
str_pad нету аналога
str_shuffle нету аналога Можно разбить строку на массив символов, использовать shuffle() и собрать обратно в строку
strcasecmp нету аналога Можно привести обе строки в нижний регистр с помощью mb_strtolower() и сравнить с помощью класса Collator из расширения intl
strcmp, strcoll нету аналога Можно использовать класс Collator из расширения intl для сравнения и сортировки строк с учетом правил нужного языка, смотрите урок про сравнение строк
strlen mb_strlen
strpos mb_strpos
strrev нету аналога Можно разбить строку на массив символов, перевернуть массив с помощью array_reverse и склеить обратно
strtolower mb_strtolower
strtoupper mb_strtoupper
substr mb_substr
ucfirst нету аналога Можно отрезать первый символ с помощью mb_substr(), перевести в верхний регистр с помощью mb_strtoupper() и приклеить остаток строки
ucwords mb_convert_case с опцией MB_CASE_TITLE

Вот список менее популярных функций, которые тоже не поддерживают utf-8 и которые не стоит использовать: chunk_split, count_chars, levenshtein, similar_text, str_ireplace, stripos, str_split, str_word_count, strchr, strcspn, stristr, strnatcasecmp, strnatcmp, strncasecmp, strncmp, strpbrk, strrchr, strripos, strspn, strstr, strtok, substr_compare, substr_count, substr_replace, wordwrap.

Латиница и цифры кодируются в utf-8 одним байтом, с ними устаревшие функции работают, но все равно, не стоит использовать эти функции — это слишком ненадежно и легко сделать ошибку.

Эти функции работают корректно с utf-8: addslashes(), stripslashes(), explode(), implode(), htmlspecialchars(), nl2br(), number_format(), str_repeat(), strtr() при использовании с 2 аргументами (с массивом, а не со строками).

Функция trim() (и ltrim() , rtrim() ) работает корректно с utf-8 только если мы отрезаем символы из ASCII, кодирующиеся одним байтом (например, перенос строки, пробел или латинскую букву). В других случаях, если, например, написать trim(‘миша вова’, ‘м’) , она воспринимает букву м , закодированную двумя байтами, как два символа, и корежит исходную строку.

Функции из семейства printf/scanf (fprintf, vprintf, sprint, sscanf и тд) ошибочно считают длины строк в байтах, а не в символах. Например, printf(«%10s», «азъ») посчитает, что «азъ» состоит из 6 символов и добавит 4 пробела для выравнивания, а не 7.

Чтобы работать с кирилицей (и другими нелатинскими) буквами в регулярках, надо ставить в конце флаг u : preg_match(«/[абвг]/u», $string) . Иначе preg_match будет думать, что работает с однобайтной кодировкой latin-1 и будет видеть не одну русскую букву, а 2 символа (так как русская буква кодируется как 2 байта). Например, буква л , кодирующаяся как 208 187 , будет восприниматься как 2 символа с кодами 208 и 187 , то есть л (в кодировке latin-1). Регулярка будет работать некорректно.

Разбиение строки на символы

Строку в utf-8 можно разбить на массив символов таким кодом:

Пустое регулярное выражение «срабатывает» на границах между буквами, а опция PREG_SPLIT_NO_EMPTY удаляет из массива два пустых элемента в начале и конце. Это позволяет использовать функции работы с массивами вроде array_reverse(). Собрать строку обратно из массива можно с помощью $str = implode(«», $chars); .

Сравнение строк по алфавиту

Обычное сравнение строк в PHP ( if ($s1 > $s2) ) просто сравнивает байты, из которых они состоят, и не учитывает правила сортировки строк, которые зависят от языка. В этом уроке про корректную сортировку строк описано, как можно для этого использовать класс Collator из расширения intl.

В Юникоде, кроме обычных, есть комбинирующие символы, которые позволяют добавлять какой-нибудь диакритический знак идущему перед ними символу. Например, буква m̊ составлена из символов m и знака кружочка над буквой. В utf-8 это кодируется как 109 (буква m), 204 , 138 (знак кружочка). При печати эти 2 «символа» (которые правильно называть code points) комбинируются в одну графему (сгенерировать такие символы можно на сайте https://symbols.typeit.org/ ).

Если мы попробуем использовать функцию strlen(«m̊ «), она вернет 3 — число байт, mb_strlen() вернет 2 — число использованных code points. Это может приводить к проблемам, например, если мы попробуем отрезать первый символ с помощью mb_substr(), то мы получим лишь букву m, а символ кружочка останется отдельно.

Для решения этой проблемы в PHP в расширении intl есть функции работы с графемами. Вот пример их использования:

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

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