2009-09-24 2 views
4
function seems_utf8($str) { 
$length = strlen($str); 
for ($i=0; $i < $length; $i++) { 
    $c = ord($str[$i]); 
    if ($c < 0x80) $n = 0; # 0bbbbbbb 
    elseif (($c & 0xE0) == 0xC0) $n=1; # 110bbbbb 
    elseif (($c & 0xF0) == 0xE0) $n=2; # 1110bbbb 
    elseif (($c & 0xF8) == 0xF0) $n=3; # 11110bbb 
    elseif (($c & 0xFC) == 0xF8) $n=4; # 111110bb 
    elseif (($c & 0xFE) == 0xFC) $n=5; # 1111110b 
    else return false; # Does not match any model 
    for ($j=0; $j<$n; $j++) { # n bytes matching 10bbbbbb follow ? 
    if ((++$i == $length) || ((ord($str[$i]) & 0xC0) != 0x80)) 
    return false; 
    } 
} 
return true; 
} 

У меня этот код из Wordpress, я мало знаю об этом, но я хотел бы знать, что именно происходит в этой функции.Проверьте, не закодирована ли строка в виде UTF-8

Если кто-нибудь знает, пожалуйста, помогите мне?

Мне нужно четкое представление о вышеуказанном коде. Если объяснение по строкам будет более полезным.

ответ

8

Я использую два способа, чтобы проверить, если строка в кодировке UTF-8 (в зависимости от случая):

mb_internal_encoding('UTF-8'); // always needed before mb_ functions, check note below 
if (mb_strlen($string) != strlen($string)) { 
/// not single byte 
} 

- ИЛИ -

if (preg_match('!\S!u', $string)) { 
// utf8 
} 

Для mb_internal_encoding - из-за какой-то неизвестный для меня ошибка в php (версия 5.3- (не проверила ее на 5.3)) передача кодировки в качестве параметра функции mb_ не работает, и внутренняя кодировка должна быть установлена ​​перед любым использованием функций mb_.

+0

Так просто сделать 'mb_strlen ($ строка, 'UTF-8')' т курица. –

7

Этот алгоритм в основном проверяет, соответствует ли последовательность байтов шаблону, который вы можете видеть в Wikipedia article.

Цикл for должен пройти через все байты в $str. ord получает десятичное число текущего байта. Затем это число проверяется на некоторые свойства.

Если число, если оно меньше 128 (0x80), это однобайтовый символ. Если он равен или больше 128, проверяется длина многобайтового символа. Это может быть сделано с первым символом многобайтовой последовательности символов. Если первый байт начинается с 110xxxxx, это двухбайтовый символ; 1110xxxx, это трехбайтовый символ и т. Д.

Я думаю, что наиболее загадочными частями являются выражения типа ($c & 0xE0) == 0xC0. То есть проверить, имеет ли число в двоичном формате определенный шаблон. Я попытаюсь объяснить, как это работает на одном примере.

Поскольку все числа, которые мы тестируем для этого шаблона, равны или больше 0x80, первый байт всегда равен 1, поэтому шаблон ограничен не менее 1xxxxxxxx. Если мы затем сделать побитовое И сравнение с 11100000 (0xE0), мы получаем это этот результат:

1xxxxxxx 
& 11100000 
= 1xx00000 

Таким образом, биты в положении 5 и 6 (читать справа, индекс начинается с 0) зависит от каков наш текущий номер. Для того, чтобы иметь, что равно 11000000, 5-й бит должен быть 0 и шестой бит должен быть 1:

1xxxxxxx 
& 11100000 
≟ 11000000 
    ↓↓ 
→ 110xxxxx 

Это означает, что остальные биты нашего числа могут быть произвольными: 110xxxxx. И это именно то, что шаблон в статье Википедии предсказывает для первого байта двухбайтового символьного слова.

И последний внутренний цикл for должен проверить правильность следующих байтов многобайтового символа. Все они должны начинаться с 10xxxxxx.

6

Если вы немного знаете о UTF-8, это довольно простая реализация.

function seems_utf8($str) { 
# get length, for utf8 this means bytes and not characters 
$length = strlen($str); 

# we need to check each byte in the string 
for ($i=0; $i < $length; $i++) { 

    # get the byte code 0-255 of the i-th byte 
    $c = ord($str[$i]); 

    # utf8 characters can take 1-6 bytes, how much 
    # exactly is decoded in the first character if 
    # it has a character code >= 128 (highest bit set). 
    # For all <= 127 the ASCII is the same as UTF8. 
    # The number of bytes per character is stored in 
    # the highest bits of the first byte of the UTF8 
    # character. The bit pattern that must be matched 
    # for the different length are shown as comment. 
    # 
    # So $n will hold the number of additonal characters 

    if ($c < 0x80) $n = 0; # 0bbbbbbb 
    elseif (($c & 0xE0) == 0xC0) $n=1; # 110bbbbb 
    elseif (($c & 0xF0) == 0xE0) $n=2; # 1110bbbb 
    elseif (($c & 0xF8) == 0xF0) $n=3; # 11110bbb 
    elseif (($c & 0xFC) == 0xF8) $n=4; # 111110bb 
    elseif (($c & 0xFE) == 0xFC) $n=5; # 1111110b 
    else return false; # Does not match any model 

    # the code now checks the following additional bytes 
    # First in the if checks that the byte is really inside the 
    # string and running over the string end. 
    # The second just check that the highest two bits of all 
    # additonal bytes are always 1 and 0 (hexadecimal 0x80) 
    # which is a requirement for all additional UTF-8 bytes 

    for ($j=0; $j<$n; $j++) { # n bytes matching 10bbbbbb follow ? 
    if ((++$i == $length) || ((ord($str[$i]) & 0xC0) != 0x80)) 
    return false; 
    } 
} 
return true; 
} 

Между прочим. На PHP я предполагаю, что это фактор 50-100 медленнее, чем функция C, поэтому вы не должны использовать ее на длинных строках и производственных системах.

0

споткнулся этот пост, был подобный вопрос .. mb_detect_encoding показал UTF-8, но mb_check_encoding вернулся ложь ...

, чтобы исправить это, для меня решение было:

$cur_encoding = mb_detect_encoding($in_str) ; 
    if($cur_encoding == "UTF-8" && mb_check_encoding($in_str,"UTF-8")) 
    return $in_str; 
    else 
    return utf8_encode($in_str); 

получил его от есть: http://board.phpbuilder.com/showthread.php?10368156-mb_check_encoding%28-in_str-quot-UTF-8-quot-%29-return-different-results

СРЮ не смог разместить ссылку правильно ....

 Смежные вопросы

  • Нет связанных вопросов^_^