LINUX.ORG.RU

Поддержка unicode в программе


0

0

Нужно сделать программу на си с нормальной поддержкой unicode.
В уникоде используется wchar_t вместо char, сразу возникают такие вопросы:

1)параметры командной строки передаются как char*, как их получить в wchar_t?
2)Если функция требует побайтового ввода (char), то каким образом туда загнать wchar_t символы?

Получил sha256 хеш строки в питоновом скрипте - один результат, получил на си с помощью libgcrypt - другой результат. Есть серьезное подозрение, что это именно из-за того, что использовалось разное представление символов.


Ответ на: комментарий от anonymous

недопонял вопрос.
"1)параметры командной строки " - имеется ввиду char **argv?

если это так, то зачем "как их получить в wchar_t"?

1. "char*" cast в "unsigned char*", e.g.
unsigned char *абвгд = (unsigned char*)argv[2]ж
2. символы со значением > 128 - русские.
на пример в KOI8-R
абвгд[0] == 0xC1
абвгд[1] == 0xC2
абвгд[2] == 0xD7
абвгд[3] == 0xC4

их уникод коды находятся в
ftp://www.unicode.org/Public/MAPPINGS/VENDORS/MISC/KOI8-R.TXT

т.е.
а - 0x0430
б - 0x0431
в - 0x0432
г - 0x0434

... а дальше, что хотите, то и делаете ...

Valeriy_Onuchin ★★
()
Ответ на: комментарий от Valeriy_Onuchin

> unsigned char *абвгд = (unsigned char*)argv[2]ж

Жжош.

А если исходная строка в UTF-8?

execve
()

Значит так. Unicode != wchar_t (вендузятник чтоли с их WCHAR?).

Есть разные способы кодирования Unicode. UTF-8 - это char*, UCS-2 - это 16-ти разрядные числа, UCS-4 - это вообще 32 разряда.

execve
()
Ответ на: комментарий от execve

приведенный пример работает с UTF-8, windows-1251, koi8-r,
iso-8859-5, cp-886, MacCyrillic, etc.
UTF-16 - это экзотика.

интересный вопрос, а используемая консоль, как GUI application,
может превращать unicode -> char?
++
stdin/stdout могут быть и в "бесконсольных application" ...

Valeriy_Onuchin ★★
()
Ответ на: комментарий от Valeriy_Onuchin

"UCS and Unicode are first of all just code tables that assign integer numbers to characters"

по-русски это означает, что на входе имеется
многобайтовая строка, а на выходе _ОДНОбайтовая_.
Именно она поступает в argv.

Valeriy_Onuchin ★★
()
Ответ на: комментарий от Valeriy_Onuchin

> что на входе имеется многобайтовая строка, а на выходе _ОДНОбайтовая_.

У Вас, похоже, проблемы с терминологией. UTF-8 - многобайтовая кодировка. Однобайтовой(-тной) кодировкой называют только такие, в которых на один символ приходится один байт, т.е. KOI8-R или ISO-8851-9. Юникод и старые восточноазиатские кодировки (ISO-2022-*, EUC-*, ...) многобайтны.

Also, никакой перекодировки командной строки, по крайней мере в C, не производится. В argv то же самое, что и было подано, как шелл держал строку в кодировке локали, так те же байтики и придут, никаких преобразований не производится.

anonymous
()
Ответ на: комментарий от Valeriy_Onuchin

обьясняю популярно:
1. нажимаем клавишу 'Б'.

2. клавиатура генерит key_code, который поступает в GUI программу
(на пример, gnome-terminal).

3. gnome-terminal превращает key_code в unicode. Заметим, что
значение уникода символа Б одинаковое для всех 16битных кодировок.
К ним относятся windows-1251, koi8-r, iso-8859-5, cp-886, MacCyrillic.
Можем проверить. Открываем и смотрим файлы:

ftp://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1251.TXT
ftp://www.unicode.org/Public/MAPPINGS/VENDORS/MISC/KOI8-R.TXT
ftp://www.unicode.org/Public/MAPPINGS/ISO8859/8859-5.TXT
ftp://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP866.TXT
ftp://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/MAC/CYRILLIC.TXT

значение уникода символа Б - 0x0411
именно поэтому уникод называется уникодом (!)

4. программа gnome-terminal
зная, какая сейчас установлена локаль - знает кодировку,
хотя есть и другие способы.
Допустим кодировка у нас - KOI8-R

5. Зная кодировку и используя mapping from
ftp://www.unicode.org/Public/MAPPINGS/VENDORS/MISC/KOI8-R.TXT
получаем 8битное значение символа Б.
В нашем случае оно равно - 0xE2, или 226

6. именно это значение поступает в argv

7. Для "Поддержка unicode в программе" - нужна обратная процедура.
Именно она описана в коде, который я привел выше.





Valeriy_Onuchin ★★
()
Ответ на: комментарий от Valeriy_Onuchin

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

can3p
() автор топика
Ответ на: комментарий от Valeriy_Onuchin

> gnome-terminal превращает key_code в unicode

За именно gnome-terminal не ручаюсь, в него еще переводировщик встроен, так что ему имеет определенный смысл думать про Unicode, но в контексте текущей локали, если без перекодировок, то есть XmbLookupString()... Впрочем, неважно

> для всех 16битных кодировок. К ним относятся windows-1251, koi8-r, [...]

Мсье, Вы меня убиваете наповал. CP1251 относится к 16-битным кодировкам? (кстати, что это такое вообще? это которые фиксированные 16-bit-per-symbol a-la UCS-2 что-ли?)

> именно это значение поступает в argv

Какое отношение имеет argv к эмулятору терминала? Да, некое косвенное, конечно, есть, ну так хоть про xargs вспомните хотя бы.

argv не имеет никакого понятия о кодировках, он может почти чем угодно питаться. Просто шелл сует ему строку в текущей локали, вот и все объяснение. А gnome-terminal здесь не при чем.

anonymous
()
Ответ на: комментарий от can3p

> Если кодировка - UTF-8, и для одного символа используется от одного до четырех байтов, то почему все работает при количестве использованных байтов больше одного?

Что значит - "работает"? Если "разломать" символ посередине, например, то работать не будет.

Да, и кодировка строки, переданной argv не UTF-8, а любая. Обычно, по соглашению - кодировка локали, LC_CTYPE. А вообще в argv может не строка (правильно читать: не представление строки) оказаться, а просто набор байт. Вопрос только в том, что конкретная программа ожидает получить и все.

> Получил sha256 хеш строки в питоновом скрипте - один результат, получил на си с помощью libgcrypt - другой результат.

SHA не работает со строками, оно работает с наборами байт. Так что да, все зависит от того что ей подадут. О том, что ей дали строку оно не знает в принципе. Ну и, видимо, да, Python ей сунул что-то одно, а C - другое.

Надо смотреть на два исходника, а так - гадание на кофейной гуще.

anonymous
()
Ответ на: комментарий от anonymous

> gnome-terminal

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

> CP1251 относится к 16-битным кодировкам

извиняюсь, глупость ляпнул :)

> шелл сует ему строку в текущей локали, вот и все объяснение.

да, вроде как так.
Вопрос на встречу, как это делается по виндами?
Там вроде никакого шелла нет.

Valeriy_Onuchin ★★
()
Ответ на: комментарий от Valeriy_Onuchin

>anonymous

спасибо.
на самом деле, я сейчас как раз с этим разбираюсь - как
работать с разными кодировками, на разных платформах (X11, win32).
То есть, сам я еще новичок в этом вопросе.
Но надеюсь - разберусь. Хочется локализировать
(хотя бы добавить кирилицу) в проект, в котором я задействован
http://root.cern.ch/

Кстати, что можно сказать о GNU readline + unicode?

Valeriy_Onuchin ★★
()
Ответ на: комментарий от anonymous

>Надо смотреть на два исходника, а так - гадание на кофейной гуще.

Заработало самым простым способом.
На си:
char salt[32];
gcry_md_hash_buffer(GCRY_MD_SHA256,salt,argv[2],strlen(argv[2]));

Питон:
from Crypto.Hash import SHA256
import sys

hash = SHA256.new()
hash.update(sys.argv[1])

Другое дело, что локаль ru_RU.UTF-8, видимо этим успех и объясняется. Насколько знаю, в питоне все строки представлены в юникоде, соответственно косяки начнутся видимо с локалями, отличными от UTF-8. Хотелось бы это сделать независимым от текущей локали.

can3p
() автор топика
Ответ на: комментарий от can3p

0. просмотрел заутро куеву тучу доков

1. хороший обзор:
http://www.unifont.org/iuc27/html/img0.html

1. Доки Ивана Паскаля:
http://pascal.tsu.ru/other/xkb/problems.html

3. http://www.freesource.info/wiki/TZ/XorgUnicode

4.
http://czyborra.com/utf/#UTF-8

5. хорошая фанк:
http://cvs.gnome.org/viewcvs/at-spi/registryd/ucs2keysym.c?rev=1.1.2.1&vi...

6.
посмотрел, как работает с unicode, UTF-8 X11 input/dislay

7.
посмотрел, как работает с unicode, UTF-8 Xft

8.
ощутил прояснение в мозгу :)

Valeriy_Onuchin ★★
()
Ответ на: комментарий от Valeriy_Onuchin

>интересный вопрос, а используемая консоль, как GUI application, >может превращать unicode -> char?

Вопрос из серии может автомобиль быть лошадью

cvv ★★★★★
()
Ответ на: комментарий от Valeriy_Onuchin

> Вопрос на встречу, как это делается по виндами?

Есть там шелл, cmd.exe. Кодировка консоли тоже как-то задается (ctcp codepage, что-ли...) Вот деталей, увы, не знаю. Система в событии KeyPress посылает уже и скан-код и код символа, это точно, а дальше что происходит - никогда не вдавался в детали.

> Кстати, что можно сказать о GNU readline + unicode?

С 5-й версии умеет. Вроде бы, если не путаю, определяет все по текущей локали (LC_CTYPE). Увы, серьезно с readline не работал.

-----

@can3p (11.09.2007 10:35:38)

> Насколько знаю, в питоне все строки представлены в юникоде, соответственно косяки начнутся видимо с локалями, отличными от UTF-8.

Нет, в Python есть и "бинарные" и "юникодные" строки, как два разных типа, так что не должно.

Гм... Честно говоря, странно. Если и в том и в том случае вывести строку ('"' + argv[n] + '"') - одинаковые данные выведет?

anonymous
()
Ответ на: комментарий от watashiwa_daredeska

> Феерично. До чего народ дошел, кодировку уже осилить не могут...

Слова не мужа, но мальчика, не знакомого с проблемой.

Если планируется что-то серьезное, то я бы порекомендовал использовать библиотеку icu http://www-306.ibm.com/software/globalization/icu/index.jsp

anonymous
()
Ответ на: комментарий от Valeriy_Onuchin

> 1. нажимаем клавишу 'Б'.

> 2. клавиатура генерит key_code, который поступает в GUI программу (на пример, gnome-terminal).

Ты здесь потерял 1.5 в лице xkb.

anonymous
()
Ответ на: комментарий от anonymous

> Слова не мужа, но мальчика, не знакомого с проблемой.

С какой проблемой? Преобразовать _числа_ (в мат. смысле, безотносительно их представления в ЭВМ) в различные формы (aka UCS-2LE/BE, UTF-8, ...)? Или выяснить из переменных среды локаль, определяющую кодировку 8-битных строк на входе/выходе программы? Или преобразовать по таблице одни _числа_ в другие (KOI8-R<->Unicode, KOI8-R<->CP1251, ...)?

Хорошо, последнее в некотором смысле является проблемой ввиду объема данных, т.к. кодировок много. Но для решения этой проблемы есть хоть та же ICU, упомянутая тобой, хоть iconv, однако эта проблема не прозвучала. Проблема нормализации Unicode-строк также не звучала. Значит, проблема одна из первых двух? Вот об этом я и говорю.

watashiwa_daredeska ★★★★
()
Ответ на: комментарий от watashiwa_daredeska

Приветствую экспертов!
прокоментируйте, пожалуйста, цитату из
http://www.freesource.info/wiki/TZ/XorgUnicode
начиная со слов " ...и могут работать"

"
и нужно пользоваться Xmb Lookup String? или XwcLookupString для получения символов в wchar и Xutf8LoookupString для получения в utf8. Последние функции используют XIC (контекст ввода) и могут работать одновременно только с одним языком ввода (русский/греческий и пр.).
"

Valeriy_Onuchin ★★
()
Ответ на: комментарий от Valeriy_Onuchin

еще один вопрос, не в тему локализации, а русификации проекта:
какие есть open source аналоги (programs, libs, databases) qt linguist?

Valeriy_Onuchin ★★
()
Ответ на: комментарий от Valeriy_Onuchin

> прокоментируйте, пожалуйста, цитату из

А чего там комментировать? xorg -- большой проект с длительной историей. Вкрутить в такую махину 100% поддержку Unicode -- тяжелая задача не потому, что Unicode сложен, а потому, что xorg большой.

watashiwa_daredeska ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.