Подтвердить что ты не робот

Как заменить/удалить 4 (+) - байтовые символы из строки UTF-8 в PHP?

Кажется, MySQL не поддерживает символы с более чем 3 байтами в своей кодировке UTF-8 по умолчанию.

Итак, в PHP, как я могу избавиться от всех 4 (-и больше) -байтных символов в строке и заменить их чем-то вроде какого-то другого символа?

4b9b3361

Ответ 1

ПРИМЕЧАНИЕ. Вы не должны просто снимать, но заменять с помощью символа замены U + FFFD, чтобы избежать атак из Unicode, в основном XSS:

http://unicode.org/reports/tr36/#Deletion_of_Noncharacters

preg_replace('/[\x{10000}-\x{10FFFF}]/u', "\xEF\xBF\xBD", $value);

Ответ 2

Поскольку 4-байтовые последовательности UTF-8 всегда начинаются с байтов 0xF0-0xF7, следующее должно работать:

$str = preg_replace('/[\xF0-\xF7].../s', '', $str);

В качестве альтернативы вы можете использовать preg_replace в режиме UTF-8, но это, вероятно, будет медленнее:

$str = preg_replace('/[\x{10000}-\x{10FFFF}]/u', '', $str);

Это работает, потому что 4-байтовые последовательности UTF-8 используются для кодовых точек в дополнительных Unicode-плоскостях, начиная с 0x10000.

Ответ 3

Вот пример:

<?php 

 mb_internal_encoding("UTF-8");

 //utf8 string,  13 bytes, 9 utf8 chars, 7 ASCII, 1 in latin1, 1 outside the BMP
 $str = "qué \xF0\x9D\x92\xB3 tal"; 
 $array = mbStringToArray($str);
 print "str: [$str]  strlen:" . strlen($str) . " chars:" . count($array) . "\n";
 $str1 = "";
 foreach($array as $c) {
   //  print "$c : " .  strlen($c)  ."\n";
   $str1 .= strlen($c)<=3? $c : '?';
 }
 print "[$str1]\n";


 function mbStringToArray ($str) {
    if (empty($str)) return false;
    $len = mb_strlen($str);
    $array = array();
    for ($i = 0; $i < $len; $i++) {
        $array[] = mb_substr($str, $i, 1);
    }
    return $array;
 }

Или, немного более компактный и эффективный:

<?php /// 

 mb_internal_encoding("UTF-8");

 //utf8 string,  13 bytes, 9 utf8 chars, 7 ASCII, 1 in latin1, 1 outside the BMP
 $str = "qué \xF0\x9D\x92\xB3 tal";
 $str1 = trimOutsideBMP($str);
 print "original: [$str]\n";
 print "trimmed:  [$str1]\n";


 // Replaces non-BMP characters in the UTF-8 string by a '?' character 
 // Assumes UTF-8 default encoding ( if not sure, call first mb_internal_encoding("UTF-8"); )
 function trimOutsideBMP($str) {
    if (empty($str)) return $str;
    $len = mb_strlen($str);
    $str1 = '';
    for ($i = 0; $i < $len; $i++) {
        $c = mb_substr($str, $i, 1);
        $str1 .= strlen($c) <= 3 ? $c : '?';
    }
    return $str1;
 }

Ответ 4

Возник этот вопрос, пытаясь решить мою собственную проблему (Facebook выплескивает некоторые смайлики в виде 4-байтовых символов, Amazon Mechanical Turk не принимает 4-байтовые символы).

В итоге я использовал это, не требует расширения mbstring:

function remove_4_byte($string) {
    $char_array = preg_split('/(?<!^)(?!$)/u', $string );
    for($x=0;$x<sizeof($char_array);$x++) {
        if(strlen($char_array[$x])>3) {
            $char_array[$x] = "";
        }
    }
    return implode($char_array, "");
}

Ответ 5

Ниже функция изменяет 3 и 4 байта символов из строки utf8 в '#':

function remove3and4bytesCharFromUtf8Str($str) {
        return preg_replace('/([\xF0-\xF7]...)|([\xE0-\xEF]..)/s', '#', $str);
    }

Ответ 6

Вот моя реализация, чтобы отфильтровать 4-байтовые символы

$string = preg_replace_callback(
    '/./u',
    function (array $match) {
        return strlen($match[0]) >= 4 ? null : $match[0];
    },
    $string
);

вы можете настроить его и заменить null (который удаляет char) с помощью некоторой строки-заменителя. Вы также можете заменить >= 4 на некоторую другую проверку длины байта.