подсчет символов юникода в с ++ - PullRequest
2 голосов
/ 27 августа 2010

Как вы считаете юникод символов в файле UTF-8 на C ++? Возможно, если кто-то будет так любезен, покажет мне «автономный» метод или, альтернативно, краткий пример, используя http://icu -project.org / index.html .

РЕДАКТИРОВАТЬ : Важное предостережение заключается в том, что мне нужно строить счетчики для каждого символа, поэтому я не считаю общее количество символов, а количество вхождений набора символов.

Ответы [ 5 ]

9 голосов
/ 27 августа 2010

В UTF-8 не ведущий байт всегда имеет верхние два бита, установленные на 10, поэтому просто игнорируйте все такие байты. Если вы не возражаете против дополнительной сложности, вы можете сделать больше (пропустить вперед не ведущие байты на основе битовой комбинации старшего байта), но в действительности это вряд ли будет иметь большое значение, за исключением коротких строк (потому что как правило, вы все равно будете близки к пропускной способности памяти).

Редактировать: Первоначально я неправильно прочитал ваш вопрос как просто вопрос о том, как считать длину строки символов, закодированных в UTF-8. Если вы хотите посчитать символьные частоты, вы, вероятно, захотите преобразовать их в UTF-32 / UCS-4 , тогда вам понадобится какой-то разреженный массив для подсчета частот.

Сложная часть этого относится к подсчету кодовых очков против символов. Например, рассмотрим символ «А» - «латинская заглавная буква А с могилой». Есть как минимум два разных способа создания этого персонажа. Вы можете использовать кодовую точку U + 00C0, которая кодирует все это в одной кодовой точке, или , вы можете использовать кодовую точку U + 0041 (латинская заглавная буква A), за которой следует кодовая точка U + 0300 (объединение серьезного акцента) .

Нормализация (относительно Unicode) означает превращение всех таких символов в одну и ту же форму. Вы можете объединить их все в одну кодовую точку или разделить их на отдельные кодовые точки. Для ваших целей, возможно, проще объединить их в одну кодовую точку, когда это возможно. Написание этого самостоятельно, вероятно, не очень практично - я бы использовал API нормализатора из проекта ICU.

4 голосов
/ 27 августа 2010

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

while (*p != 0)
{
    if ((*p & 0x80) == 0 || (*p & 0xc0) == 0xc0)
        ++count;
    ++p;
}

Или, как отмечено в комментариях, вы можете просто пропустить каждый байт, который является продолжением:

while (*p != 0)
{
    if ((*p & 0xc0) != 0x80)
        ++count;
    ++p;
}

Или, если вы хотите быть очень умным и сделать его 2-строчным:

for (p; *p != 0; ++p)
    count += ((*p & 0xc0) != 0x80);

* Страница Википедии для UTF-8 четко показывает шаблоны.

3 голосов
/ 09 декабря 2011

Я знаю, уже поздно для этой темы, но это может помочь

с ICU, я сделал это так:

string TheString = "blabla" ;
UnicodeString uStr = UnicodeString::fromUTF8( theString.c_str() ) ;
cout << "length = " << uStr.length( ) << endl ;
3 голосов
/ 27 августа 2010

Обсуждение с полной рутиной, написанной на C ++, находится по адресу http://www.daemonology.net/blog/2008-06-05-faster-utf8-strlen.html

0 голосов
/ 27 августа 2010

Я бы не стал считать это языковым вопросом.Формат UTF-8 довольно прост;декодирование из файла должно состоять из нескольких строк кода на любом языке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...