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