Как получить число кодовой точки для данного символа в строке utf-8?

18
задан Erik Kalkoken 16 October 2018 в 13:32
поделиться

3 ответа

Scott Reynen записал, что функция к преобразовывает UTF-8 в Unicode. Я нашел его смотрящий документация PHP .

function utf8_to_unicode( $str ) {

    $unicode = array();        
    $values = array();
    $lookingFor = 1;

    for ($i = 0; $i < strlen( $str ); $i++ ) {
        $thisValue = ord( $str[ $i ] );
    if ( $thisValue < ord('A') ) {
        // exclude 0-9
        if ($thisValue >= ord('0') && $thisValue <= ord('9')) {
             // number
             $unicode[] = chr($thisValue);
        }
        else {
             $unicode[] = '%'.dechex($thisValue);
        }
    } else {
          if ( $thisValue < 128) 
        $unicode[] = $str[ $i ];
          else {
                if ( count( $values ) == 0 ) $lookingFor = ( $thisValue < 224 ) ? 2 : 3;                
                $values[] = $thisValue;                
                if ( count( $values ) == $lookingFor ) {
                    $number = ( $lookingFor == 3 ) ?
                        ( ( $values[0] % 16 ) * 4096 ) + ( ( $values[1] % 64 ) * 64 ) + ( $values[2] % 64 ):
                        ( ( $values[0] % 32 ) * 64 ) + ( $values[1] % 64 );
            $number = dechex($number);
            $unicode[] = (strlen($number)==3)?"%u0".$number:"%u".$number;
                    $values = array();
                    $lookingFor = 1;
          } // if
        } // if
    }
    } // for
    return implode("",$unicode);

} // utf8_to_unicode
8
ответ дан 30 November 2019 в 08:10
поделиться

Используйте существующую утилиту такой в качестве iconv, или независимо от того, что библиотеки идут с языком, который Вы используете.

, Если Вы настаиваете на том, чтобы прокручивать свое собственное решение, читайте на формат UTF-8. В основном каждая кодовая точка хранится как 1-4 байта, в зависимости от значения кодовой точки. Диапазоны следующие:

  • U+0000 — U+007F: 1 байт: U+0080 †0xxxxxxx
  • ” U+07FF: 2 байта: 110xxxxx 10xxxxxx
  • U+0800 — U+FFFF: 3 байта: 1110xxxx 10xxxxxx 10xxxxxx
  • U+10000 — U+10FFFF: 4 байта: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

, Где каждый x является битом данных. Таким образом можно сказать, сколько байтов составляет каждую кодовую точку путем рассмотрения первого байта: если это начинается с 0, это - 1-байтовый символ. Если это начинается 110, это - 2-байтовый символ. Если это начинается с 1110, это - 3-байтовый символ. Если это начинается 11110, это - 4-байтовый символ. Если это начинается 10, это - неначальный байт многобайтового символа. Если это начинается 11111, это - недопустимый символ.

, Как только Вы выясняете, сколько байтов находится в символе, это - просто вопрос если битовое жонглирование. Также обратите внимание, что UCS-2 не может представить символы выше U+FFFF.

, Так как Вы не определили язык, вот является некоторый образец C кодом (опущенная проверка ошибок):

wchar_t utf8_char_to_ucs2(const unsigned char *utf8)
{
  if(!(utf8[0] & 0x80))      // 0xxxxxxx
    return (wchar_t)utf8[0];
  else if((utf8[0] & 0xE0) == 0xC0)  // 110xxxxx
    return (wchar_t)(((utf8[0] & 0x1F) << 6) | (utf8[1] & 0x3F));
  else if((utf8[0] & 0xF0) == 0xE0)  // 1110xxxx
    return (wchar_t)(((utf8[0] & 0x0F) << 12) | ((utf8[1] & 0x3F) << 6) | (utf8[2] & 0x3F));
  else
    return ERROR;  // uh-oh, UCS-2 can't handle code points this high
}
12
ответ дан 30 November 2019 в 08:10
поделиться

Я удивлен, потому что я просто дал эту проблему студентам на итоговом экзамене. Вот эскиз UTF-8:

hex         binary                   UTF-8 binary
0000-007F   00000000 0abcdefg   =>   0abcdefg
0080-07FF   00000abc defghijk   =>   110abcde 10fghijk
0800-FFFF   abcdefgh ijklmnop   =>   1110abcd 10efghij 10klmnop

И вот некоторый код C99:

static void check(char c) {
  if ((c & 0xc0) != 0xc0) RAISE(Bad_UTF8);
}

uint16_t Utf8_decode(char **p) { // return code point and advance *p
  char *s = *p;
  if ((s[0] & 0x80) == 0) {
    (*p)++;
    return s[0];
  } else if ((s[0] & 0x40) == 0) {
    RAISE (Bad_UTF8);
    return ~0; // prevent compiler warning
  } else if ((s[0] & 0x20) == 0) {
    if ((s[0] & 0xf0) != 0xe0) RAISE (Bad_UTF8);
    check(s[1]); check(s[2]);
    (*p) += 3;
    return ((s[0] & 0x0f) << 12)
         + ((s[1] & 0x3f) <<  6)
         + ((s[2] & 0x3f));
  } else {
    check(s[1]);
    (*p) += 2;
    return ((s[0] & 0x1f) << 6)
         + ((s[1] & 0x3f));
  }
}    
4
ответ дан 30 November 2019 в 08:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: