Конвертация массива байтов в UTF-8
Модератор: Модераторы
Конвертация массива байтов в UTF-8
Чем в RTL лучше сортировать массивы байтов в символы UTF-8? AnsiToUtf8 и UTF8ENCODE на выходе выдают какой-то мусор, есть ли смысл брутфорсить лучшие функции или их там нет?
А что у вас лежит в массиве байтов?
UTF-8 символы, в файлы их же записывают по байтам а после чтения файла сортируют: в этот UTF-8 символ кладём 1 байт, в другой 2, в третий 4 подряд идущих байта. Для одного русского языка можно написать конвертер, потому что логика сортировки байтов по символам для этой кодировки не очевидна, а для остальных языков как?
Сортировка -- это упорядочивание чего-либо.
Однако, из ваших слов похоже, что речь идет о разборе последовательности символов в UTF-8 (префиксный код) на их числовые значения (code points) 16 или 32-битные. При разборе действительно определяется, в скольких байтах закодирован символ: http://ru.wikipedia.org/wiki/UTF-8
Далее был упомянут русский язык, то есть полученные коды предполагалось оставить в Unicode (UTF-32) либо преобразовать в ту или иную кодовую таблицу русского языка: 1251, 866, koi8-R, ISO-8859-5, ...
Что именно из перечисленного имелось в виду? Только разбор на "символы" UTF-8 в виде String[6]?
Или всё же перевод из однобайтовый кодировки в UTF-8, первое сообщение больше на это похоже... Тогда как определили, что получился именно мусор, а не значение в UTF-8?
Добавлено спустя 29 минут 49 секунд:
Если возьмем в качестве примера слово "Сквозняк", то его представление в памяти будет таким (для UTF-16 и UTF-32 показано low endian (Intel) представление):
Однако, из ваших слов похоже, что речь идет о разборе последовательности символов в UTF-8 (префиксный код) на их числовые значения (code points) 16 или 32-битные. При разборе действительно определяется, в скольких байтах закодирован символ: http://ru.wikipedia.org/wiki/UTF-8
Далее был упомянут русский язык, то есть полученные коды предполагалось оставить в Unicode (UTF-32) либо преобразовать в ту или иную кодовую таблицу русского языка: 1251, 866, koi8-R, ISO-8859-5, ...
Что именно из перечисленного имелось в виду? Только разбор на "символы" UTF-8 в виде String[6]?
Или всё же перевод из однобайтовый кодировки в UTF-8, первое сообщение больше на это похоже... Тогда как определили, что получился именно мусор, а не значение в UTF-8?
Добавлено спустя 29 минут 49 секунд:
Если возьмем в качестве примера слово "Сквозняк", то его представление в памяти будет таким (для UTF-16 и UTF-32 показано low endian (Intel) представление):
Код: Выделить всё
С к в о з н я к
cp1251: d1 ea e2 ee e7 ed ff ea
cp866: 91 aa a2 ae a7 ad ef aa
koi8-r: f3 cb d7 cf da ce d1 cb
8859-5: c1 da d2 de d7 dd ef da
С к в о з н я к
utf-8: d0 a1 d0 ba d0 b2 d0 be d0 b7 d0 bd d1 8f d0 ba
utf-16: 21 04 3a 04 32 04 3e 04 37 04 3d 04 4f 04 3a 04
С к в о
з н я к
utf-32: 21 04 00 00 3a 04 00 00 32 04 00 00 3e 04 00 00
37 04 00 00 3d 04 00 00 4f 04 00 00 3a 04 00 00
c BOM:
utf-8: ef bb bf
d0 a1 d0 ba d0 b2 d0 be d0 b7 d0 bd d1 8f d0 ba
utf-16: ff fe
21 04 3a 04 32 04 3e 04 37 04 3d 04 4f 04 3a 04
utf-32: ff fe 00 00
21 04 00 00 3a 04 00 00 32 04 00 00 3e 04 00 00
37 04 00 00 3d 04 00 00 4f 04 00 00 3a 04 00 00
bormant писал(а):Что именно из перечисленного имелось в виду? Только разбор на "символы" UTF-8 в виде String[6]?
Да, этого пока достаточно. С разбором байтов #0..#127 по String[6] всё ясно, а вот с байтами #128..#255 что-то не очень. Если бы точно знать, что считать маркером обозначающим начало символа, то было бы проще.
Так ссылку не зря выше давал, там процесс кодирования подробно и понятно описан.
(b and $80) = 0 -- один символ
(b and $E0) = $C0 -- два байта, второй должен начинаться с (b and $C0) = $80, иначе рассинхронизация
(b and $F0) = $E0 -- три байта, каждый из которых должен начинаться с (b and $C0) = $80, иначе рассинхронизация
...
Собрав значащие биты, получите число -- номер символа в юникоде, в однобайтовую кодировку -- по таблице кодировки. Именно этим занимаются функции Utf8To...
(b and $80) = 0 -- один символ
(b and $E0) = $C0 -- два байта, второй должен начинаться с (b and $C0) = $80, иначе рассинхронизация
(b and $F0) = $E0 -- три байта, каждый из которых должен начинаться с (b and $C0) = $80, иначе рассинхронизация
...
Собрав значащие биты, получите число -- номер символа в юникоде, в однобайтовую кодировку -- по таблице кодировки. Именно этим занимаются функции Utf8To...
В десятичных, неассемблерных числах таблица шифровки UTF-8 выглядит проще и пригоднее к использования без побитовых операций:
Байты 0..127 - однобайтовый символ.
Байты 128...191 - 2..6-ой байт многобайтового символа
Первый байт 2 байтового символа - 192..223
Первый байт 3 байтового символа - 224..239
Первый байт 4 байтового символа - 240..247
Первый байт 5 байтового символа - 248..251
Первый байт 6 байтового символа - 252..253
Как видно, UTF-8 можно расширить и до 7-8 байтных символов: для первого байта свободны значения 254..255.
Байты 0..127 - однобайтовый символ.
Байты 128...191 - 2..6-ой байт многобайтового символа
Первый байт 2 байтового символа - 192..223
Первый байт 3 байтового символа - 224..239
Первый байт 4 байтового символа - 240..247
Первый байт 5 байтового символа - 248..251
Первый байт 6 байтового символа - 252..253
Как видно, UTF-8 можно расширить и до 7-8 байтных символов: для первого байта свободны значения 254..255.
Еще скажите, что "b in [192..223]" отличается по сути чем-либо от "b and $E0=$C0"...
При вычисленных значениях можно использовать оператор case, а во вторых, шестнадцатеричные числа ещё надо перевести в десятичные чтобы понять "а сколько это" - английские буквы вместо цифр не слишком удобны для запоминания, всей пользы от них что они есть на стандартной клавиатуре и экономят символы при наборе. А операторы "or" и "and" перед применением ещё желательно протестировать - а вдруг они на этих типах данных поведут себя нестандартно.
Проще работать в UTF32, там все предсказуемо
Правда память будет жрать
Правда память будет жрать
Ism писал(а):Проще работать в UTF32
В линуксе её поддержка около нуля, да и компилятор её не поймёт - тоже не поддерживает. Вот и приходится ковыряться в каках.
Сквозняк писал(а): Если бы точно знать, что считать маркером обозначающим начало символа, то было бы проще.
Читайте вики
sign писал(а):Читайте вики
Википузия плохой сайт на котором крышу держат свидетели искривления пространства, нет смысла лишний раз его читать, когда ответ уже получен http://freepascal.ru/forum/viewtopic.php?p=84410#p84410 Вот http://www.wikiznanie.ru правильная энциклопедия, её и надо поддеоживать
Сквозняк писал(а):sign писал(а):Читайте вики
Википузия плохой сайт на котором крышу держат свидетели искривления пространства, нет смысла лишний раз его читать, когда ответ уже получен http://freepascal.ru/forum/viewtopic.php?p=84410#p84410 Вот http://www.wikiznanie.ru правильная энциклопедия, её и надо поддеоживать
Если жаждущий ответа сразу бы припал к вики, то тут же бы получил ответ и ему не пришлось бы его выспрашивать тут.
А насчёт викизнания, то вот вам два результата поиска в каждом ресурсе по слову utf8.
Первый, википедия:
Второй, ваше викизнание:
Я лично считаю, что хороший тон - сперва поискать. Там, сям, а потом, когда не получится, спрашивать уже у людей на форумах.
В 90%, ответы уже где-то, кем-то написаны. Если не лениться, то их можно найти.
Кстати, очень часто ответы на чисто технические (не политизированные) вопросы уже даны в википедии.
Именно поэтому я и дал рекомендацию заглядывать туда.
У вас нет необходимых прав для просмотра вложений в этом сообщении.
Если жаждущий ответа сразу бы припал к вики, то тут же бы получил ответ и ему не пришлось бы его выспрашивать тут.
Если все будут читать только вики, то откуда появится аналогичная информация на форумах? А потом с единственным источником информации случится что-то нехорошее и поисковики при запросе покажут дырку от бублика. Куда приятнее, когда пишешь в поисковик "паскаль вопрос такой-то" и находишь сразу несколько ответов. А если про паскаль нигде не спрашивать, то и поисковики обленятся про него искать, в лучшем случае закопают ответ глубоко-глубоко.
