Неразрывное пространство utf-8 0xc2a0 и preg_replace странное поведение

В моей строке у меня есть неиспользуемое пространство utf-8 (0xc2a0), и я хочу заменить его чем-то другим.

Когда я использую

$str=preg_replace('~\xc2\xa0~', 'X', $str);

он работает нормально.

Но когда я использую

$str=preg_replace('~\x{C2A0}~siu', 'W', $str);

неразрывное пространство не найдено (и заменено).

Почему? Что не так со вторым регулярным выражением?

Формат \x{C2A0} правильный, также я использовал флаг u.

Ответ 1

Собственно, документация об escape-последовательностях в PHP неверна. Когда вы используете синтаксис \xc2\xa0, он ищет символ UTF-8. Но с синтаксисом \x{c2a0} он пытается преобразовать последовательность Unicode в кодированный символ UTF-8.

Неразрывное пространство U+00A0 (Unicode), но кодированное как C2A0 в UTF-8. Поэтому, если вы попробуете шаблон ~\x{00a0}~siu, он будет работать, как ожидалось.

Ответ 2

У меня есть предыдущие ответы aggegate, поэтому люди могут просто скопировать/вставить следующий код, чтобы выбрать свой любимый метод:

$some_text_with_non_breaking_spaces = "some text with 2 non breaking spaces at the beginning";
echo 'Qty non-breaking space : ' . substr_count($some_text_with_non_breaking_spaces, "\xc2\xa0") . '<br>';
echo $some_text_with_non_breaking_spaces . '<br>';

# Method 1 : regular expression
$clean_text = preg_replace('~\x{00a0}~siu', ' ', $some_text_with_non_breaking_spaces);

# Method 2 : convert to bin -> replace -> convert to hex
$clean_text = hex2bin(str_replace('c2a0', '20', bin2hex($some_text_with_non_breaking_spaces)));

# Method 3 : my favorite
$clean_text = str_replace("\xc2\xa0", " ", $some_text_with_non_breaking_spaces);

echo 'Qty non-breaking space : ' . substr_count($clean_text, "\xc2\xa0"). '<br>';
echo $clean_text . '<br>';

Ответ 3

Два кода делают разные вещи, на мой взгляд: первый \xc2\xa0 заменит TWO символов, \xc2 и\xa0 ничем.

В кодировке utf-8 это оказывается кодовым пунктом для U + 00A0

работает\x {00A0}? Это должно быть представление для\xc2\xa0

Ответ 4

Я не использовал этот вариант ~\x{c2a0}~siu.

Varian \x{00A0} работает. Я не пробовал второй вариант, и вот результат:

Я попытался преобразовать его в шестнадцатеричный и заменить свободное пространство 0xC2 0xA0 (c2a0) на пробел 0x20 (20).

код:

$hex = bin2hex($item);
$_item = str_replace('c2a0', '20', $hex);
$item = hex2bin($_item);