Зачем использовать многобайтовые строковые функции в PHP?
В настоящий момент я не понимаю, почему действительно важно использовать функции mbstring в PHP при работе с UTF-8? Моя локаль под linux уже установлена на UTF-8, так почему не работает как strlen
, preg_replace
и так далее не работают должным образом по умолчанию?
5 ответов
Все строковые функции PHP не обрабатывают многобайтовые строки независимо от локали вашей операционной системы. Вот почему вам нужно использовать многобайтовые строковые функции.
Из многобайтовой строки Введение:
Когда вы манипулируете строками (обрезать, разделять, объединять и т. Д.), Закодированными в многобайтовой кодировке, вам необходимо использовать специальные функции, поскольку два или более последовательных байта могут представлять один символ в таких схемах кодирования. В противном случае, если вы примените к строке не-многобайтовую строковую функцию, она, вероятно, не сможет обнаружить начало или конец многобайтового символа и в результате получит поврежденную строку мусора, которая, скорее всего, потеряет свое первоначальное значение.
Люди здесь не понимают UTF-8.
Вам не нужно использовать код с поддержкой UTF-8 для обработки UTF-8. По большей части.
Я даже написал верхний / нижний регистр Unicode, а также преобразования NFC и NFD, используя только байтовые функции. Трудно придумать что-нибудь более сложное, чем то, что требует такой деликатной и детальной обработки UTF-8. И все же он все еще работает с байтовыми функциями.
Очень редко, когда вам нужен код с поддержкой UTF-8. Может быть, чтобы посчитать количество символов, или переместить точку вставки вперед на 1 символ. Но на самом деле даже тогда ваш код не будет работать;) из-за разложенных символов.
Но если все, что вы делаете - это замены, поиск вещей или даже синтаксический анализ, вам просто нужны функции, учитывающие байты.
Я объясню почему.
Это потому, что внутри любого другого символа UTF-8 не может быть найдено ни одного символа UTF-8. Вот как это устроено.
Попытайтесь объяснить мне, как вы можете получить ошибки обработки текста в терминах многобайтовой системы, в которой ни один символ не может быть найден внутри другого символа? Только один пример дела! Самое простое, что вы можете придумать.
Вот мой ответ на простом английском языке. Один японский, китайский и корейский символы занимают более одного байта. Например, типичный характер сказать x
Это занимает 1 байт на английском языке, это займет больше, чем 1
байт на японском и китайском и корейском. Теперь стандартные строковые функции PHP предназначены для обработки одного символа как 1 байта. Поэтому, если вы пытаетесь сравнить два японских, китайских или корейских символа, они не будут работать так, как ожидалось. Например, длина "Hello World!" на японском или китайском или корейском языке будет иметь более 12 байтов.
Строки PHP - это просто байтовые последовательности. Они не имеют никакого значения сами по себе. И они также не используют какую-либо конкретную кодировку символов.
Так что если вы читаете файл с помощью file_get_contents()
вы получаете бинарно-безопасное представление файла. Может ли это быть (двоичное) представление изображения или текстового файла, читаемого человеком - PHP не волнует.
Теперь, пока вам нужно просто выполнить базовую обработку строки, вам совсем не нужно знать кодировку символов. Так что если вы хотите сохранить строку обратно в файл, используя file_put_contents()
или хотите получить его длину (не количество символов), используя strlen()
ты в порядке.
Однако, как только вы начнете выполнять более сложные манипуляции со строками, вам необходимо знать кодировку символов! Нет способа сохранить его как часть строки, поэтому вы должны либо отслеживать его отдельно, либо, что делает большинство людей, использовать соглашение о наличии всех (текстовых) строк в общей кодировке символов, например US-ASCII или в настоящее время UTF-8.
Так как невозможно установить кодировку символов для строки, PHP не знает, какую кодировку символов использует строка. Из-за этого, единственная вменяемая вещь для strlen()
сделать - вернуть количество байтов, так как это единственное, что PHP знает наверняка.
Если вы предоставляете дополнительную информацию об используемой кодировке символов, вам нужно использовать другую функцию - функция вызывается mb_strlen()
в этом случае.
То же самое относится и к preg_replace()
: Если вы хотите заменить umlaut-a или сопоставить три одинаковых символа в строке, вам необходимо знать, как кодируется umlaut-a, и вообще, как кодируются символы.
Так что если у вас есть гипотетическая кодировка символов, которая кодирует нижний регистр a
как a1
и в верхнем регистре A
как a2
, b
как b1
а также B
как b2
(и так далее), вы можете иметь (закодированную) строку a1a1a1
который состоит из трех одинаковых символов подряд. Однако, не зная кодировку и просто взглянув на последовательность байтов, невозможно обнаружить это.
Резюме:
Нормальное "по умолчанию" невозможно, так как строки PHP не содержат кодировку символов. И даже если, одна функция, как strlen()
не может вернуть длину последовательности байтов, как требуется для Content-Length
Заголовок HTTP и в то же время количество символов также полезно для обозначения длины статьи блога.
Вот почему функция перегрузки функций по своей сути не работает, и даже если она поначалу будет выглядеть красиво, она будет плохо отлаживаться.
Рауль Гонсалес - прекрасный пример того, почему:
Речь идет о сокращении слишком длинных имен пользователей для базы данных MySQL, скажем, у нас есть ограничение в 10 символов и Raul González
.
Модульный тест ниже - это пример того, как вы можете получить такую ошибку.
Общая ошибка: 1366 Неправильное строковое значение: '\xC3' для столбца 'name' в строке 1 (SQL: update
users
установленname
= Рауль Гонзо,updated_at
= 2019-03-04 04:28:46 гдеid
= 793)
и как этого избежать
public function test_substr(): void
{
$name = 'Raul González';
$user = factory(User::class)->create(['name' => $name]);
try {
$name1 = substr($name, 0, 10);
$user->name = $name1;
$user->save();
} catch (Exception $ex) {
}
$this->assertTrue(isset($ex));
$name2 = mb_substr($name, 0, 10);
$user->name = $name2;
$user->save();
$this->assertTrue(true);
}
Для иллюстрации использовались PHP Laravel и PhpUnit.
multibyte => multi + byte.
1) Используется для работы со строкой в другом языке (значит, не на английском).
2) Строковые функции PHP по умолчанию работают только с английским (или выпущенным для него) языком.
3) Если вы хотите использовать strlen () или strpos () или uppercase () или strreplace () для специального символа,
Предположим, нам нужно применить строковые функции к "Hello".
В китайском (你好), арабском (مرحبا), японском (こんにちは), хинди (
नमस्ते), гуджарати (હેલો).
Разный язык может иметь свои собственные наборы символов
так что mbstring введен для общения с различными языками, такими как (китайский, японский и т. д.).