UTF-8 to UNICODE

Тема в разделе "WASM.ZEN", создана пользователем _DEN_, 25 авг 2005.

  1. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    Поделитесь "формулой" перевода utf-8 в unicode?
     
  2. _staier

    _staier New Member

    Публикаций:
    0
    Регистрация:
    3 окт 2003
    Сообщения:
    738
    Адрес:
    Ukraine
    а utf8 это и есть unicode

    вопрос не очень корректный

    utf8 это один из способов реализации unicode

    imho



    а вот из дельфи system.pas
    Код (Text):
    1.  
    2. function Utf8ToUnicode(Dest: PWideChar; MaxDestChars: Cardinal; Source: PChar; SourceBytes: Cardinal): Cardinal;
    3. var
    4.   i, count: Cardinal;
    5.   c: Byte;
    6.   wc: Cardinal;
    7. begin
    8.   if Source = nil then
    9.   begin
    10.     Result := 0;
    11.     Exit;
    12.   end;
    13.   Result := Cardinal(-1);
    14.   count := 0;
    15.   i := 0;
    16.   if Dest <> nil then
    17.   begin
    18.     while (i < SourceBytes) and (count < MaxDestChars) do
    19.     begin
    20.       wc := Cardinal(Source[i]);
    21.       Inc(i);
    22.       if (wc and $80) <> 0 then
    23.       begin
    24.         if i >= SourceBytes then Exit;          // incomplete multibyte char
    25.         wc := wc and $3F;
    26.         if (wc and $20) <> 0 then
    27.         begin
    28.           c := Byte(Source[i]);
    29.           Inc(i);
    30.           if (c and $C0) <> $80 then Exit;      // malformed trail byte or out of range char
    31.           if i >= SourceBytes then Exit;        // incomplete multibyte char
    32.           wc := (wc shl 6) or (c and $3F);
    33.         end;
    34.         c := Byte(Source[i]);
    35.         Inc(i);
    36.         if (c and $C0) <> $80 then Exit;       // malformed trail byte
    37.  
    38.         Dest[count] := WideChar((wc shl 6) or (c and $3F));
    39.       end
    40.       else
    41.         Dest[count] := WideChar(wc);
    42.       Inc(count);
    43.     end;
    44.     if count >= MaxDestChars then count := MaxDestChars-1;
    45.     Dest[count] := #0;
    46.   end
    47.   else
    48.   begin
    49.     while (i < SourceBytes) do
    50.     begin
    51.       c := Byte(Source[i]);
    52.       Inc(i);
    53.       if (c and $80) <> 0 then
    54.       begin
    55.         if i >= SourceBytes then Exit;          // incomplete multibyte char
    56.         c := c and $3F;
    57.         if (c and $20) <> 0 then
    58.         begin
    59.           c := Byte(Source[i]);
    60.           Inc(i);
    61.           if (c and $C0) <> $80 then Exit;      // malformed trail byte or out of range char
    62.           if i >= SourceBytes then Exit;        // incomplete multibyte char
    63.         end;
    64.         c := Byte(Source[i]);
    65.         Inc(i);
    66.         if (c and $C0) <> $80 then Exit;       // malformed trail byte
    67.       end;
    68.       Inc(count);
    69.     end;
    70.   end;
    71.   Result := count+1;
    72. end;
    73.  
    74.  
     
  3. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    staier



    UNICODE это UTF-16.

    Ща, попробую всю эту дрянь перелопатить на С++...
     
  4. _staier

    _staier New Member

    Публикаций:
    0
    Регистрация:
    3 окт 2003
    Сообщения:
    738
    Адрес:
    Ukraine
  5. Quantum

    Quantum Паладин дзена

    Публикаций:
    0
    Регистрация:
    6 янв 2003
    Сообщения:
    3.143
    Адрес:
    Ukraine
    Юникод к UTF имеет столь же отдалённое отношение, как ASCIIZ к safe-array. UTF16 очень напоминает юникод, но таковым не является, а UTF8 скорее похож на ASCII.
     
  6. noonv

    noonv Member

    Публикаций:
    0
    Регистрация:
    19 июл 2005
    Сообщения:
    209
    Адрес:
    Russia
  7. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    staier



    Спасибо, fucking web помог! :)))
     
  8. _staier

    _staier New Member

    Публикаций:
    0
    Регистрация:
    3 окт 2003
    Сообщения:
    738
    Адрес:
    Ukraine
    Quantum

    ты не прав насчёт unicode/utf8/utf16 и их отношения

    UTF-1 has only historical interest, having been removed from ISO/IEC

    10646. UTF-7 has the quality of encoding the full BMP repertoire

    using only octets with the high-order bit clear (7 bit US-ASCII

    values, [US-ASCII]), and is thus deemed a mail-safe encoding

    ([RFC2152]). UTF-8, the object of this memo, uses all bits of an

    octet, but has the quality of preserving the full US-ASCII range:

    US-ASCII characters are encoded in one octet having the normal US-

    ASCII value, and any octet with such a value can only stand for an

    US-ASCII character, and nothing else.



    UTF-16 is a scheme for transforming a subset of the UCS-4 repertoire

    into pairs of UCS-2 values from a reserved range. UTF-16 impacts

    UTF-8 in that UCS-2 values from the reserved range must be treated

    specially in the UTF-8 transformation.





    iso ucs и unicode сейчас практически одно и тоже

    хотя формальные различия имеются - unicode более строгий стандарт
     
  9. Quantum

    Quantum Паладин дзена

    Публикаций:
    0
    Регистрация:
    6 янв 2003
    Сообщения:
    3.143
    Адрес:
    Ukraine
    staier

    Я не нашёл в вышеприведенной цитате опровержения своих слов.





    И где здесь UTF? :)





    Обоснуйте, пожалуйста.
     
  10. Asterix

    Asterix New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2003
    Сообщения:
    3.576
    что-то в последнее время на wasm'е слишком много листингов

    на object pascal, опопсел? :derisive:
     
  11. _staier

    _staier New Member

    Публикаций:
    0
    Регистрация:
    3 окт 2003
    Сообщения:
    738
    Адрес:
    Ukraine
    utf-8 это iso ucs

    utf-16 это iso ucs & unicode

    utf-8 входит в utf-16 как подмножество



    Asterix

    это я "опопсел" а не wasm :derisive:



    впрочем продолжив ваш флейм замечу, что если иметь в виду популярность языка среди широких масс индусских программистов то соотношение явно в пользу с++
     
  12. Quantum

    Quantum Паладин дзена

    Публикаций:
    0
    Регистрация:
    6 янв 2003
    Сообщения:
    3.143
    Адрес:
    Ukraine
    staier

    UCS (если я правильно понял спецификацию, но речь изначально всё равно шла не о UCS) и Unicode - это схемы кодирования символов, а UTF - это формат хранения текстовых строк. Что же мы яблоки с экскаваторами сравниваем?
     
  13. _staier

    _staier New Member

    Публикаций:
    0
    Регистрация:
    3 окт 2003
    Сообщения:
    738
    Адрес:
    Ukraine
    Quantum

    что такое схема кодирования и чем она отличается от формата хранения в данном случае?



    проще говоря utf это один из механизмов в совокупности составляющих ucs соответтственно utf это элемент множества

    ucs а unicode это подмножество ucs



    utf это один из способов реализации transformation within ucs/unicode specification



    ладно , я вижу у нас идёт какой - то абстрактный спор о терминологии в котором я лично не вижу никакого практического смысла
     
  14. Quantum

    Quantum Паладин дзена

    Публикаций:
    0
    Регистрация:
    6 янв 2003
    Сообщения:
    3.143
    Адрес:
    Ukraine
    staier



    Допустим, что нам необходимо представить один или более китайских иероглифов. Решение: применяем схему кодирования (ucs или юникод). Юникод, кстати, более ограничен, чем ucs, но для simplified chinese сойдёт.



    А теперь представьте, что нам необходимо сохранить текстовую последовательность (строку, например). Решение: конвертируем то, что мы получили при помощи схемы кодирования, в формат хранения типа UTF. UTF имеет заголовок, содержащий количество символов в текстовой строке, чем отдалённо напоминает паскалевые строки.



    Также могу добавить, что UTF выбирает схему кодирования (ascii, юникод, ucs) с оптимальным размером символа под конкретную строку, т.е. "обычные" ASCII-символы в UTF занимают 1 байт, а китайские иероглифы - по 2-4 байта.





    Практического смысла действительно мало.
     
  15. DzheiKa

    DzheiKa New Member

    Публикаций:
    0
    Регистрация:
    29 май 2006
    Сообщения:
    13
    хм.. почитал я тут всего, со многим и не согласен.
    Unicode - это в общем система символов, содержащая любые азбуки, и служебные символы,
    а вот кодировка - это способ представления юникода.
    В вин32 (и не только =) принято юникодом считать символ в слово (2 байта), что не очень удобно для разных систем пересылки данных, интернета и т.д., где обычно концом сообщения является двоичный нуль. Сами представте, сколько у нас символов (в 2 байта) содержащих двоичный нуль (либо в младшем, либо в старшем байте). Конец такой юникодовской строки является тоже нуль, только в одно слово (два байта по нулю). Ввиду такой проблемы и были введены кодировки (они не содержат однобайтового нуля - он кодирует конец строки).

    Вообще, честно говоря, все винды на платформе NT для отображения текста на окнах работают только с юникодом (с тем, который двух-байтовый, а не кодировки), такие символы еще называют WideChar (широкий, или двух-байтовый, в отличие от ANSI - однобайтовой). Кто просматривал секцию ресурсов, должно быть замечал, что там тоже все только в юникоде.
    Поэтому, каждый раз, как вы вызываете ANSI версию API (для однобайтовых символов), например MessageBoxA, система тратит лишнее время на перекодирование этого сообщения в Unicode (2 byte), и только потом вызывает WideChar версию API (MessageBoxW).
    Подробно об этом можно прочитать в книге Джеффри Рихтера.

    Теперь что касается UTF-8, и в общем говоря, тот самый вопрос, что меня сюда привел.

    UTF-8 кодируется следующим образом:
    в этой кодировке один символ юникода занимает от 1 до 6 байт.
    если символ находиться в диапазоне от 0 до 80h (т.е. старший бит ведущего байта сброшен) - он 100% занимает 1 байт.
    Остальные символы кодируются по следующему алгоритму:
    первый байт назовем ведущим (выделен жирным).
    1 : 0xxxxxxx
    2 : 110xxxxx 10xxxxxx
    3 : 1110xxxx 10xxxxxx 10xxxxxx
    4 : 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
    5 : 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
    6 : 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

    Как видно, что ведущий байт не может начинаться с 10 или с 1111111, да и вообще, все, что не подходит под этот алгоритм, нарушает кодировку UTF-8.

    К примеру:
    откроем обычный блокнот (notepad), и попробуем туда записать ОЁ (2 большие русские буквы о и ё). Сохраним файлик, и заного откроем его блокнотом... да, уже видем не наши ОЁ, а греческую букву ПСИ. Все потому, что блокнот каждый раз при открытии файла проверяет его на верность кодировки UTF-8 по выше приведенному алгоритму. Если все верно, он отображает нам уже переведенную последовательно символов в юникод (вызвав функцию MultiByteToWideChar с кодовой страницей CP_UTF8 (65001)).
    В действительности что такое ОЁ : CE A8 = 11001110 10101000

    Теперь самое интересное : ввиду такого большого диапазона значений (кому не лень, можете пересчитать, сколько всего возможных символов можно получить в UTF-8) не все символы являются переводимыми в юникод (его диапазон всего лишь 65535 символов).
    Проделаем тоже самое с блокнотом, только теперь за место ОЁ запишем 4 байта : фёёё
    !!! вот так вот, переоткрыв файл мы ничего не увидим, но размер файла попрежнему 4 байта. Все верно, просто фёёё
    тоже подходит под алгоритм кодирования UTF-8, но он не имеет эквивалентного символа в юникоде.
    фёёё: F4 B8 B8 B8 = 11110100 10111000 10111000 10111000

    Эту проблему можно легко избежать, т.к. MultiByteToWideChar поддерживает такую проверку.
    Для такой проверки достаточно вызвать MultiByteToWideChar с флагом MB_ERR_INVALID_CHARS (8).
    Если кодировка не имеет перевода в юникод, то GetLastError вернет ERROR_NO_UNICODE_TRANSLATION
    Код (Text):
    1.     lea edi,[Buffer]
    2.     lea esi,[szText1]
    3.     Invoke  MultiByteToWideChar,65001,8,esi,-1,edi,0
    4.     Invoke  GetLastError
    5.     xor edx,edx
    6.     inc edx
    7.     xor eax,ERROR_NO_UNICODE_TRANSLATION
    8.     cmovnz  eax,edx
    65001 - Code page UTF-8
    8 - MB_ERR_INVALID_CHARS
    -1 - размер исходного буфера, или буфера, содержащего Мультибайтовую строку (это не юникод, а кодировка (заканчивается двоичным нулем в один байт)), указав -1 (или 0FFFFFFFFh - максимальный размер), мы указываем на то, что API сама высчитает конец строки по однобайтовому нулю.
    0 - размер конечного буфера, если мы не уверены, что у нас кодировка верна, мы ничего не переводим, а лишь только проверяем на правильность кодировки, но если указать размер, отличный от нуля, мы получим не только результат проверки, но и перекодированную мультибайтовую строку в юникод.

    Казалось бы, какие еще могут быть проблемы... Но с одной такой проблемой я и столкнулся.

    В выше приведенном примере если szText1 будет содержать "ф",0 - что никаким образом не соответствует кодировке UTF-8, мы получим ложный результат =\, GetLastError не вернет нам ERROR_NO_UNICODE_TRANSLATION.
    Эту проблему можно решить двумя способами :
    1) в размере Мультибайтового буфера указать длину нашей строки (для "ф",0 это 1)
    2) еще раз самим убедиться на правильность кодировки.

    в случае 1) нам придется вычислять дополнительно длину строки (до однобайтового двоичного нуля).
    в случае 2) нам придется проверять весь алгоритм самим.

    Конечно проще не заморачиваться на все эти биты, а просто идти по пути 1), но кто знает, может такой конфликт произойти и с указанием длины строки...
    На этот пример с "ф" я наткнулся случайно (кстати не только с "ф" такое, еще есть несколько символов).
    Может кому повезет больше, и такое не соответствие произойдет и с указанием длины буфера.

    На всякий случай приведу пример кода, для тех, кто пойдет по пути 2) =)
    Код (Text):
    1. IsUTF8String        proc    stdcall Src:DWORD
    2.     nop
    3. org $-4
    4.     pushad
    5.     mov esi,[esp+4+20h]
    6.    
    7. IsUTF8_MainLoop:
    8.     xor ebx,ebx
    9.     lodsb
    10.     test    al,al
    11.     jz  Short IsUTF8_ret
    12.     test    al,80h
    13.     jz  Short IsUTF8_MainLoop
    14.  
    15.     or  ecx,-1  ;ecx=-1
    16.     shl al,1
    17. @@:
    18.     inc ecx
    19.     shl al,1
    20.     jc  Short @B
    21.    
    22.     or  ebx,-1
    23.     jecxz   Short IsUTF8_ret
    24. @@:
    25.     lodsb
    26.     and al,11000000b
    27.     xor al,80h
    28.     jnz Short IsUTF8_ret
    29.     dec ecx
    30.     jnz Short @B
    31.     mov esi,esi
    32.     jmp Short IsUTF8_MainLoop
    33.    
    34. IsUTF8_ret:
    35.     inc ebx
    36.     mov [esp+1Ch],ebx   ;eax in stack
    37.     popad
    38.     retn    4
    39. IsUTF8String        endp
    есть более оптимизированный вариант (по времени выполнения)
    Код (Text):
    1. IsUTF8String        proc    stdcall Src:DWORD
    2.     nop
    3. org $-4
    4.     pushad
    5.     mov esi,[esp+4+20h]
    6.    
    7. IsUTF8_MainLoop:
    8.     xor ebx,ebx
    9.     lodsb
    10.     test    al,al
    11.     jz  Short IsUTF8_ret
    12.     shl al,1
    13.     jnc Short IsUTF8_MainLoop
    14.                     ;al=1 xxxxxxx
    15.     or  ebx,-1
    16.     shl al,1
    17.     jnc Short IsUTF8_ret    ;al=1 0 ...... not utf8
    18.     shl al,1
    19.     jnc Short IsUTF8_2b     ;al=11 0 xxxxx
    20.     shl al,1
    21.     jnc Short IsUTF8_3b     ;al=111 0 xxxx
    22.     shl al,1
    23.     jnc Short IsUTF8_4b     ;al=1111 0 xxx
    24.     shl al,1
    25.     jnc Short IsUTF8_5b     ;al=11111 0 xx
    26.     shl al,1
    27.     jc  Short IsUTF8_ret    ;al=111111 0 x
    28. IsUTF8_6b:
    29.     mov eax,[esi]
    30.     add esi,4
    31.     and eax,0C0C0C0C0h
    32.     xor eax,080808080h
    33.     jnz Short IsUTF8_ret
    34. IsUTF8_2b:
    35.     mov al,[esi]
    36.     and al,0C0h
    37.     xor al,080h
    38.     jnz Short IsUTF8_ret
    39.     inc esi
    40.     jmp Short IsUTF8_MainLoop
    41. IsUTF8_3b:
    42.     mov eax,[esi]
    43.     and eax,0C0C0h
    44.     xor eax,08080h
    45.     jnz Short IsUTF8_ret
    46.     inc esi
    47.     inc esi
    48.     jmp Short IsUTF8_MainLoop
    49. IsUTF8_4b:
    50.     mov eax,[esi]
    51.     and eax,0C0C0C0h
    52.     xor eax,0808080h
    53.     jnz Short IsUTF8_ret
    54.     add esi,3
    55.     jmp Short IsUTF8_MainLoop
    56. IsUTF8_5b:
    57.     mov eax,[esi]
    58.     add esi,4
    59.     and eax,0C0C0C0C0h
    60.     xor eax,080808080h
    61.     jz  Short IsUTF8_MainLoop
    62.    
    63. IsUTF8_ret:
    64.     inc ebx
    65.     mov [esp+1Ch],ebx   ;eax in stack
    66.     popad
    67.     retn    4
    68. IsUTF8String        endp
     
  16. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    Кодировки вроде бы были введены задолго до создания юникода :)

    Отнюдь не всё, только строки.

    В остальном довольно познавательно.
     
  17. DzheiKa

    DzheiKa New Member

    Публикаций:
    0
    Регистрация:
    29 май 2006
    Сообщения:
    13
    Ну на самом деле по поводу ввода, вернее причин ввода, кодировок чисто ИМХО, или я бы даже сказал предположение. Хотя набрался смелости выложить =). Так или иначе спасибо, что поправил =).

    А вот с оптимизированным вариантом я лажанулся =), но уже подправил, ведь специально расположил проверку на 2-х байтовый вариант (тест 1 байта) сразу за проверкой на 6-байтовый вариант, но зачем-то продублировал один и тот же код =). Да и джампы теперь все короткие =).
     
  18. ava

    ava New Member

    Публикаций:
    0
    Регистрация:
    11 окт 2003
    Сообщения:
    169
    Всем-всем-всем: чтобы больше не лажаться, открываем http://ru.wikipedia.org/wiki/Юникод и внимательно читаем статью от начала до конца.
     
  19. DzheiKa

    DzheiKa New Member

    Публикаций:
    0
    Регистрация:
    29 май 2006
    Сообщения:
    13
    я ее уже читал =)
     
  20. ava

    ava New Member

    Публикаций:
    0
    Регистрация:
    11 окт 2003
    Сообщения:
    169
    Прочитай еще раз.