LINUX.ORG.RU

C++ Ломаный юникод для кирилических символов.

 , , ,


0

1

Не получается работать с кириллицей из плюсовой программы:
Если вхардкодить кириллическую строку, она и в файл и в stdout выводится как надо, в нужной локали, и все верно,
но стоит попытаться прочитать оную кирилицу из файла, stdin или, как в моем случае - получить от tesseract-ocr, вся кириллица (но не цифры) превращается в d0 (или 208) - символ Ð

Первый раз понадобилось, и тут такая ересь Оо
Скрин из дебагера

UPD: Товарищ с stackoverflow подсказал что у меня юникод невалидный - русские символы должны занимать 2 байта - d0 + код символа.
Очевидно, что-то в моей генте не так, но что?

Локали есть:

(1/4) Generating en_US.ISO-8859-1 ...
(2/4) Generating en_US.UTF-8 ...
(3/4) Generating ja_JP.UTF-8 ...
(4/4) Generating ru_RU.UTF-8 ...

★★★★★

Последнее исправление: mersinvald (всего исправлений: 1)

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

А он ничего не даст. Но если так нужно, то держи, мне не жалко)

int main()
{
    setlocale(LC_ALL, "ru_RU.UTF-8");
    char c;
    cin >> c; //вводим любой кириллический символ, получаем в памяти 208
    cout << c << std::endl; //получаем Ð
    return 0;
}

Что с сетлокалью, что без.

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

Окей, запишу я его в int16*, а дальше то как с ним работать?
Да и метод tesseract getUTF8Text возвращает char*. И нет, там не отводится по две однобайтные переменные на символ.

mersinvald ★★★★★
() автор топика

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

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

exactly.
Раз уж я тут, не подскажешь чем можно удобно работать в плюсах с юникодными символами в несколько байт?

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

Юникод то имеет свойство занимать переменное число байт

Unicode — это абстрактное описание символов и «кодовых точек». В конкретной кодировке символы могут занимать как переменное число байт (UTF-8, UTF-16), так и постоянное (UTF-32).

i-rinat ★★★★★
()
Ответ на: комментарий от mersinvald

Юникод то имеет свойство занимать переменное число байт...

Не Юникод, а UTF-8. Если конкретнее, то UTF-8 занимает от 1 до 4 мест по 8-бит. Переводя в тип С:

typedef struct {
    /* в зависимости от символа 
     * "эффективными" могут быть не все байты
     *
     * https://en.wikipedia.org/wiki/UTF-8#Description
     */
    unsigned char data[4];
} utf8_char_t;

/* закодированная UTF-8 строка 
 * SIZE != реальной длинне строки (количеству codepoint-ов)
 * нет оверхеда по памяти
 */
unsigned char utf8_string[SIZE];

/* UTF-8 строка "по символам" 
 * LENGTH == реальная длинна строки
 * На каждый символ от 0 до 3 байт оверхеда
 */
utf8_char_t utf8_char_string[LENGTH];

Для сравнения: UTF-16 занимает 1 или 2 места по 16 бит:

typedef struct {
    /* https://en.wikipedia.org/wiki/UTF-16#Examples
     */
    uint16_t data[2];
} utf16_char_t;

/* закодированная UTF-16 строка
 * SIZE != реальной длинне
 * Нет оверхеда (если не считать ASCII символы по 16 бит оверхедом). 
 */
uint16_t utf16_string[SIZE];

/* UTF-16 строка "по символам"
 * LENGTH == реальная длинна строки
 * На каждый символ 0 *или* 2 байта оверхеда
 */
utf16_char_t utf16_char_string[LENGTH];

Т.е. UTF-8 и UTF-16 являются кодировками а не Юникодом. В данный момент юникод помещается в диапазон [0 .. 2^32]. Что делает UTF-32 прямым представлением юникода (без «кодирования»).

Важно понимать внутренее принципиальное представление этих кодировок, чтоб понимать правила их обработки.

P.S. Также есть разновидности: UTF-16BE, UTF-16LE, UTF-32BE, UTF-32LE (Big / Little Edian). Эти разновидности указывают на порядок байт. Упражнение: догадайся почему не существует UTF-8BE или UTF-8LE?

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

UTF-8 занимает от 1 до 4 мест по 8-бит

До 6-ти, вообще-то. Это важно, т. к. в примере выше может вызвать переполнение буфера.

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

До 6-ти, вообще-то.

В оригинале да. Но стандартом его урезали до 4-х. https://en.wikipedia.org/wiki/UTF-8#Description

The original specification covered numbers up to 31 bits (the original limit of the Universal Character Set). In November 2003, UTF-8 was restricted by RFC 3629 to end at U+10FFFF, in order to match the constraints of the UTF-16 character encoding. This removed all 5- and 6-byte sequences, and 983040 4-byte sequences.

По этому я бы не волновался за отсутствующие дополнительные два байта. Просто код, работающий с UTF-8 должен считать байты 111110xx и 1111110x невалидным началом UTF-8 последовательности.

KennyMinigun ★★★★★
()
Последнее исправление: KennyMinigun (всего исправлений: 2)
Ответ на: комментарий от KennyMinigun

О, спасибо за инфу, я бы так и не заметил. Я, главное, по ссылке прошел, а до этого места не дочитал.

2003

И ведь давно уже так.

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

Окей, запишу я его в int16*,

может лучше в string? на худой конец в char* ?

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

а дальше то как с ним работать?

что значит «работать»? ввод/вывод/поиск символа (как поиск строки) делается стандартно, как и с любыми строками. вставку в неконец/замену символа проще всего сделать созданием новой строки. ещё вопросы?

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

нет, utf8 имеет свойство занимать переменное число байт

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