Можно ли безопасно использовать str_replace в кодированной кодировке UTF-8, если в качестве аргументов заданы только строки с кодировкой UTF-8?

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 принимает фиксированные байты и заменяет … В результате у нас есть что-то, что не является символом мусора и т. Д.

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