PHP str_replace()
предназначался только для строк ANSI и, как таковой, мог искажать строки UTF-8. Однако, учитывая, что он двоично-безопасный, будет ли он работать правильно, если в качестве аргументов были заданы только строки UTF-8?
Изменить: я не ищу функцию замены, я просто хотел бы знать, правильна ли эта гипотеза.
Да. UTF-8 преднамеренно спроектирован таким образом, чтобы разрешить эту и другие аналогичные обработки, не поддерживающие Unicode.
В UTF-8 любая последовательность байтов, отличных от ASCII, представляющая действительный символ, всегда начинается с байта в диапазоне \xC0-\xFF
. Этот байт не может появляться нигде в последовательности, поэтому вы не можете сделать действительную последовательность UTF-8, которая соответствует части символа.
Это не относится к старым многобайтовым кодировкам, где разные части байтовой последовательности неразличимы. Это вызвало множество проблем, например, попытку заменить обратную косую черту ASCII в строке Shift-JIS (где byte \x5C
может быть вторым байтом последовательности символов, представляющей что-то еще).
Это правильно, потому что многобайтовые символы UTF-8 являются исключительно символами не-ASCII (128+ байтов), начинающимися с байта, который определяет, сколько байтов следует, поэтому вы не можете случайно совместить часть одного многобайтового символа UTF-8 с другой.
Чтобы визуализировать (абстрактно):
a
для символа ASCII 2x
для 2-байтового символа 3xx
для 3-байтового символа 4xxx
для 4-байтового символа Если вы соответствуете, скажем, a2x3xx
(байты в диапазоне ASCII), так a
< x
и 2x
не могут быть подмножеством 3xx
или 4xxx
и т. Д., Вы можете быть уверены, что ваш UTF-8 будет соответствовать правильно, учитывая предпосылка, что все строки определенно действительны UTF-8.
Изменить: см. Ответ bobince для менее абстрактного объяснения.
Ну, у меня есть встречный пример: у меня есть кодированные UTF8 параметры «.ini», в которых указаны параметры приложения, такие как имя отправителя электронной почты. В нем написано что-то вроде:
email_from = Märta
и я прочитал его оттуда переменному $sender
. Теперь, когда я заменяю тело сообщения (снова UTF8)
привет {отправитель}
$message = str_replace("{sender}",$sender_name,$message);
Письмо абсолютно верно во всех отношениях, но отправитель полностью сломан. Существуют и другие случаи (например, explode ()), когда что-то происходит с строкой UTF. Это здорово до конверсии, но не после него. Извините, что, похоже, нет способа исправить это поведение.
Edit : На самом деле, explode()
участвует в разборе файла .ini, поэтому проблема может быть в самой этой функции, поэтому str_replace()
может быть невиновным.
Нет, ты не можешь.
Из практики я говорю вам, если у вас есть несколько многобайтовых символов, таких как ◊ и т. Д., А другие не многобайтные, они не будут работать корректно, потому что есть символы, которые занимают 2-4 места, str_replace
принимает фиксированные байты и заменяет … В результате у нас есть что-то, что не является символом мусора и т. Д.
Да, я думаю, это правильно, по крайней мере, я не смог найти контр-пример.