2015-12-12 6 views
1

Мне нужно сделать код, который принимает символы с кодировкой UTF-8 и «переводит» их в Unicode. Здесь вы можете проверить, что такое UTF-8: https://en.wikipedia.org/wiki/UTF-8. Я начинающий C поэтому у меня есть три ограничения, наложенные на меня:Кодирование UTF-8 в C с getchar()

  1. я должен использовать getchar()
  2. запрещено использовать массивы
  3. Я заинтересован только в символах Unicode с 1,2,3 и 4 байта

Поэтому у меня есть этот код, который является полностью функциональным для 4 байта (я знаю, что я должен использовать != EOF для каждого getchar();, но сейчас это не моя проблема)

#include <stdio.h> 

int main(void) { 
     int ch1, ch2, ch3, ch4, c; 
     ch1 = getchar(); 
     ch2 = getchar(); 
     ch3 = getchar(); 
     ch4 = getchar(); 
     if ((ch1 & 0xF8) != 0xF0 || (ch2 & 0xC0) != 0x80 || 
         (ch3 & 0xC0) != 0x80 || (ch4 & 0xC0) != 0x80) { 
       printf("Error in UTF-8 4-byte encoding\n"); 
       return 1; 
     } 
     c = ((ch1 & 0x07) << 18) | ((ch2 & 0x3F) << 12) | 
         ((ch3 & 0x3F) << 6) | (ch4 & 0x3F); 
     printf("c = %05X\n", c); 
     return 0; 
} 

Мой вопрос: я не могу понять, как я могу использовать getchar() для 1-2-3 байта. Я имею в виду, что я должен прочитать все функции getchar в начале, а затем использовать ch1 для 1-байтовых символов и ch1, ch2 для двухбайтовых символов. Или я должен сделать это следующим образом. (Кстати, код ниже, это не работает, это дает мне бесконечный цикл,. Я просто использовать его в качестве примера моей мысли)

#include <stdio.h> 

int main (void) { 
     int ch1, ch2, ch3, ch4, c; 

     if (c >=0x0000 && c<=0x007F){ 
      ch1=getchar(); 
      while (ch1 !=EOF){ 
       if ((ch1 & 0x80) != 0x00) { 
        printf("Error in UTF-8 1-byte encoding\n"); 
        return 1; 
        } 
       c = ((ch1 & 0x80) << 7); 
       printf("c = %05X\n", c); 
       } 
     } 
+0

Обратите внимание, что UTF-8 не нуждается в более чем 4 байтах, поскольку Unicode ограничивается диапазоном U + 0000 .. U + 10FFFF. Действительно, некоторые байты - 0xC0, 0xC1 и 0xF5 .. 0xFF не могут отображаться в действительном UTF-8. См. Также [Действительно хорошие, плохие примеры тестовых данных UTF-8] (https://stackoverflow.com/questions/1319022/really-good-bad-utf-8-example-test-data) –

ответ

4

Вы не можете сделать это первым чтением четырех символов а затем решает, что делать. Если персонаж находится в 0x00-0x7f, вы будете бросать остальную часть, или вам придется обрабатывать их сложнее.

Правильный способ - прочитать один символ. Он расскажет вам, сколько дополнительных символов вам нужно, если они есть, на основе наиболее значимых бит, составляющих 1 с. Затем прочитайте дополнительные и преобразуйте в правильную кодовую точку UNICODE, сдвинув и отклонив наиболее важные бит, когда это необходимо.

Вы можете проверить связанную документацию, чтобы узнать, как биты кода кода UNICODE распределены по нескольким байтам. Здесь также приводится краткое описание алгоритма:

  • Читать один байт
  • Если верхний бит равен нулю, нет ничего другого делать: точка код 0x00-0x7f
  • Если верхний три бит 110, то вам нужен один дополнительный байт. Возьмите пять младших бит первого байта, сдвиньте их влево на шесть бит и ИЛИ младшие шесть бит со второго байта, чтобы получить окончательное значение
  • Если самые верхние четыре бита - 1110, вам понадобятся два дополнительных байта. Возьмите четыре младших бита первого, сдвиг на 12 бит или шесть младших бит из второго байта, сдвинутого на шесть, затем, наконец, шесть младших бит третьего байта
  • Если самые верхние пять бит - 11110, тогда вам нужно три дополнительного байт и будете читать их, сдвиг и т.д., как ранее
  • Если ни одно из этих условий не подходят, данные некорректны
  • Обратите внимание, что при чтении дополнительных байт, эти байты должны быть 10 как наиболее значимыми биты; ничего другого недействительно.

Нижний код не будет работать даже, так как c никогда не дается значение, поэтому условие if будет неопределенным.Он тоже не проверяет байты, так что код вам не поможет.

+0

ok Я понял ваш ответ о нижний код ... но я не уверен, что полностью понимаю, что вы имеете в виду в своем втором абзаце. Можете ли вы объяснить это больше, пожалуйста? – navarian

+0

@kostasdi Добавлено объяснение, что делать –

+1

Это охватывает основы - он будет читать действительные UTF-8 и отклонить вопиюще недействительный UTF-8 (и может быть достаточно для OP). Для полной проверки есть некоторые дополнительные требования, такие как: отклонение не минимальных кодировок (0xC0 0x80 - не минимальная и, следовательно, некорректная кодировка для U + 0000, допустимая кодировка - 0x00); Суррогаты UTF-16 (U + D800..U + DFFF) не допускаются; значения вне диапазона U + 0000..U + 10FFFF недействительны. –

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