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