Можно ли безопасно использовать 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 для символа ASCII
  • 2x для 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 принимает фиксированные байты и заменяет... В результате мы получаем что-то, что не является мусором символов и т. д.

Да, я думаю, что это правильно, по крайней мере, я не смог найти контрпример.

Другие вопросы по тегам