LINUX.ORG.RU

Кто как получает на C / C++ utf8 (utf16) string из пользовательских данных?


1

1

Убогость стандартных библиотек C & C++ поражает воображение. Как можно нормально сконвертировать что-то, что передаётся в программу извне, в utf формат. iconv не очень вдохновляет громозкостью кода и неспособностью работать с отдельными символами многобайтных кодировок.

Хочу один раз написать фукнцию (утилиту) для конвертации строк, чтобы решить хотя бы эту каждодневную задачу.

unicode.org раньше предоставлял reference UTF-8/16/32 converter. Там всего два файла, ConvertUTF.h и ConvertUTF.с.

Conversions between UTF32, UTF-16, and UTF-8.

С 2004 года библиотеку убрали с сайта (здесь немного подробностей: http://stackoverflow.com/questions/2685004/why-does-unicode-org-no-longer-off...), но ее можно найти в разных проектах (в clang, например). Или вот здесь: http://gears.googlecode.com/svn/trunk/third_party/convert_utf/

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

задача в том, чтобы из кодировки, которую я не знаю как обрабатывать, получить кодировку, которую я умею обрабатывать. wchar_t, например, к таковым не относится.

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

непредсказумее чем с wchar_t.

у wchar_t даже литералы (\xABCD) impelementation-dependent. к тому же, нет способа получения из wchar_t того же utf-8. Могучая libc такого не умеет.

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

Общая замена на ? невозможна.

скорее всего так.

*inbuf is left pointing to the beginning of the invalid multibyte sequence.

кстаті надо проверіть может он показывает на начало той самой крівой последовательності. Тогда можно выдавать корректный мэсадж.

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

1) каждый автор либы для компилятора знает как он работает. Я этого знать не могу

2) htons пишется через a) #ifdef b) трюки, которые позволяют определить endianness (переносимых трюков compile-time я не знаю)

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

конечно же этот код должен работать под linux, freebsd, win32. :)

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

mbtowc + setlocale в пр

wchar_t out;
char x[] = {0xc5, 0xac};
char *locale_backup = setlocale(«en_GB.UTF-8»); // может работать, а может послать. В BSD & шынде пошлёт явно.
mbtowc(&out, x, 2); // out теперь содержит L'ŭ', если система поддерживает;
setlocale(LC_ALL, locale_backup);

Работать может в однопоточном режиме. Ну и держится всё на соплях.

Я такое за реализацию принять не могу.

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

задача в том, чтобы из кодировки, которую я не знаю как обрабатывать, получить кодировку, которую я умею обрабатывать. wchar_t, например, к таковым не относится.

а чего уметь в wchar_t? там всё просто — один wchar == один символ. Что тут сложного-то? Не понимаю...

у wchar_t даже литералы (\xABCD) impelementation-dependent.

ну и что? Вам не хватает 4х байт? Простите — подо-что???

к тому же, нет способа получения из wchar_t того же utf-8. Могучая libc такого не умеет.

вы совсем упоролись. Вот, для самых маленьких:

http://ru.wikipedia.org/wiki/Utf-8

для маленьких Ъ

    Первый байт содержит количество байтов символа, закодированное в единичной системе счисления;

1 - 0
2 — 11
3 — 111
4 — 1111
5 — 11111
6 — 111111

слева число байт, справа — первые биты первого байта. Таблицу я дополнил. Что может быть проще-то?

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

из wchar_t на/в твою UTF16-LE.

это невозможно сделать кроссплатформенно.

если символ влезает в wchar_t, то возможно. Иначе задача теряет смысл, ибо теряют смысл входные данные. Для Linux это происходит с пятибайтовыми символами. Но я не слышал, что такие символы IRL использует кто-то.

Про маздай я некомпетентен. Не знаю, и знать не желаю.

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

кстаті надо проверіть может он показывает на начало той самой крівой последовательності.

что ты проверять решил, лолка? В мане английским по чёрному это сказано. И я уже цитировал, лолка.

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

буду рад поглядеть на код который сконвертит \u016d (ŭ) в wchar_t.

В общем случае варианты представления одного символа в кодировке UTF-8 выглядят так:

(1 байт)  0aaa aaaa 
(2 байта) 110x xxxx 10xx xxxx
(3 байта) 1110 xxxx 10xx xxxx 10xx xxxx
(4 байта) 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx
(5 байт)  1111 10xx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx
(6 байт)  1111 110x 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx
тут два байта 16D
     1 0110 1101
     101 --101101
     101 10101101
11000101 10101101
C   5    A   D

Ответ 0xC5AD

код написать сможешь, или лолка полная и окончательная?

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

Да уж: в педивикии даже привели алгоритм преобразования UTF32LE <-> UTF8!

Уж да. Какім боком тут wchar_t? Нет нормального способа в Цэ выйти на UTF _кроссплатформенно_.

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

работает он только на конкретном localhost.

man locale.

Сегодня работает: LANG=en_GB.UTF-8

Завтра не работает: LANG=en_GB.ASCII

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

держі: ііііііііііііііііііііііііііііііііііііііііііі

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

а то что даже літерал задать для wchar_t невозможно в ascii файле.

просто у тебя руки кривые.

Hint: задавай в utf-8.

PS: задолбал со своей i. Я через яти ведь не пишу? А ведь могу же, с меня станется...

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

wchar_t тут что-то не віжу.

чего ты хочешь-то? про mbtowc(3) и wctomb(3) читал? Они стандартные (see C99).

Если какой-то там маздай, или фряха из 80х годов их не умеет — пиши в их саппорт. Или сам костыляй. Винфак --> там.

Первая преобразует mb в wchar_t, вторая — обратно. Чего ты ещё хотел, лолка? Залезть в кишки и сделать по своему — ну я показал как. Не хочешь лезть — используй стандартные зонды. В чём проблема-то?

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

работает он только на конкретном localhost.

они работают ВЕЗДЕ. И ещё раз, для тех лолок, что в танке: wchar_t это ВНУТРЕННИЙ ФОРМАТ В ПАМЯТИ!!! Так понятно?

Если хочешь сохранить в файле, use utf-8. При чём тут твоя локаль, детка?

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

Если хочешь сохранить в файле, use utf-8. При чём тут твоя локаль, детка?

Talk is cheap, show me the code (wchar_t -> utf8, чтоб работало под DOS & windows & freebsd & gnu/linux)

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

сделаешь лучше?

конечно. setlocale уберу. Они тут не нужны. UTF-8 ОДНА КОДИРОВКА, она не бывает «английской». ASCIIZ последовательность

d1 85 d1 83 d0 b9 00
символизирует тебя В ЛЮБОЙ локали. Даже в китайской.

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

от упёртый... Это для print_mb задаётся. Всякие евреи так вообще справа-налево пишут, вот и задаётся предварительно.

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

print_mb:

int print_mb(const char* ptr)
{
    std::mbtowc(NULL, 0, 0); // reset the conversion state
    const char* end = ptr + std::strlen(ptr);
    int ret;
    for (wchar_t wc; (ret = std::mbtowc(&wc, ptr, end-ptr)) > 0; ptr+=ret) {
        std::wcout << wc;
    }
    std::wcout << '\n';
    return ret;
}
dzidzitop ★★
() автор топика
Ответ на: комментарий от dzidzitop

wchar_t -> utf8, чтоб работало под DOS & windows & freebsd & gnu/linux

под Linux УМВР

под венду и под дос: винфак --> там

под фряху — без понятия. Если эта фряха умеет utf-8, и компилятор (и glibc) умеют C99, то будет работать, судя по мануалу. Фряхи под рукой нет для тестов, извини.

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

mbtowc юзает локаль - так что под freebsd/windows/whatever будет сюрпрайз.

ну я тебе последовательность дал, возьми, и попробуй.

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

Я ему про Ивана, а он — про болвана! Ты из педивикии алгоритм бери, а не парь мозг какими-то левыми плюсаческими функциями!

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

рекомендую setlocale(«C») перед print_mb

а при чём тут вообще print_mb, лолка? Ты что просишь второй день? Портабельный вывод в терминал? Упоролся? С каких это пор в маздае есть портабельный терминал с utf-8???

(впрочем — яhz, может и есть, тогда будет работать. C99 гарантирует)

UPD WTF print_mb? У меня нет мана к этой хрени. Сам разбирайся со своими костылями.

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

Я ему про Ивана, а он — про болвана! Ты из педивикии алгоритм бери, а не парь мозг какими-то левыми плюсаческими функциями!

он накололся на то, очевидно, что порядок байт меняется. В итоге хрень получается, при попытке чтения из файла wchar_t. И при выводе в терминал Windows тоже(уже не из-за порядка, а из-за косорылости терминала by design).

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

Дык, я ему и говорил еще давно, что перед записью в файл надо сделать, скажем, htole16, а во время чтения — le16toh. И будет эта хрень одинаково работать на любых архитектурах.

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

он накололся на то, очевидно, что порядок байт меняется.

я накололся на то, что предполагаемый utf-8 by default не работает.

я свою проблему решіл: https://github.com/dzidzitop/libafc/blob/master/src/afc/stringToUTF16.cpp

только на подобный код глядеть не хочется.

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

я свою проблему решіл: https://github.com/dzidzitop/libafc/blob/master/src/afc/stringToUTF16.cpp

дык там у тебя какие-то нелепые костыли для маздайной UTF16. Ну а в мысы какое-то своё, особое видение юникода. Да и на wchar_t тоже как-то по своему они смотрят.

я накололся на то, что предполагаемый utf-8 by default не работает.

это у тебя UTF16 mustdie edition не работает...

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