Определите ширину в байтах символа utf-8 - PullRequest
2 голосов
/ 23 июня 2019

Итак, я пытаюсь определить ширину в байтах символа utf-8 на основе его двоичного представления.И с этим посчитайте количество символов в строке utf8.Ниже приведен мой код.

#include <stdlib.h>
#include <stdio.h>

static const char* test1 = "发f";
static const char* test2 = "ด้ดีด้ดี";

unsigned utf8_char_size(unsigned char val) {
    if (val < 128) {
        return 1;
    } else if (val < 224) {
        return 2;
    } else if (val < 240) {
        return 3;
    } else {
        return 4;
    }
}

unsigned utf8_count_chars(const unsigned char* data)
{
  unsigned total = 0;
  while(*data != 0) {
    unsigned char_width = utf8_char_size(*data);
    total++;
    data += char_width;
  }
  return total;
}

int main(void) {
  fprintf(stdout, "The count is %u\n", utf8_count_chars((unsigned char*)test1));
  fprintf(stdout, "The count is %u\n", utf8_count_chars((unsigned char*)test2));
  return 0;
}

Проблема здесь в том, что я получаю The count is 2 за первый запуск теста выше.Это имеет смысл для первого, но со вторым, test2, с 4 тайскими буквами, он печатает 8, что не правильно.

Я хотел бы знать, что мой код делает неправильно, и, более того, я хотел бы знать, учитывая массив unsigned char в C, как можно перебирать байты как символы utf-8?

1 Ответ

5 голосов
/ 23 июня 2019

Код измеряет ни символов , ни глифов , но кодовых точек . Символ может состоять из нескольких кодовых точек Юникода. В этом случае текст на тайском языке имеет 8 кодовых точек.

Строки Unicode легче проверять в Python, чем в C, поэтому вот небольшая демонстрация Python 3.6 с использованием встроенной базы данных Unicode:

>>> import unicodedata
>>> for i in 'ด้ดีด้ดี':
...     print(f'{ord(i):04X} {unicodedata.name(i)}')
... 
0E14 THAI CHARACTER DO DEK
0E49 THAI CHARACTER MAI THO
0E14 THAI CHARACTER DO DEK
0E35 THAI CHARACTER SARA II
0E14 THAI CHARACTER DO DEK
0E49 THAI CHARACTER MAI THO
0E14 THAI CHARACTER DO DEK
0E35 THAI CHARACTER SARA II
...