Команда IT специалистов выполнит подготовку инфраструктуры для вашего бизнеса.
Внедрение самых передовых решений и технологий.
Поддержка и сопровождение ваших сервисов.
Выполнение работ под "ключ", от покупки сервера, до настройки автоматизации процессов.
8(977)608-78-62 adm@nixm.ru

utf-8 в Си

Аватара пользователя
nezabudka
Местный говорун
Местный говорун
Сообщения: 618
Зарегистрирован: 18 апр 2015, 06:13
Откуда: Ростов на Дону

utf-8 в Си

Сообщение nezabudka »

Писать на Си пользовательские приложение задача не из приятных, но как еще
можно практиковаться на начальном этапе? Решила я написать себе консольное
приложение что бы упростить жизнь на работе. Задача тривиальная. Имеется
база сотрудников нашего управления. И нужно на начальном этапе организовать
поиск в базе по фамилии. Так сказать создать динамическую сортировку совпадений
по мере ввода букафъ. Зачем это надо? Фамилий много, набирать полное соответствующее
имя не хочется. И ошибки сразу на лицо если скажем совпадения не найдены. Применение
шаблонов регулярных выражений это следующий этап и забегать вперед не стану.
Какие трудности поджидали меня в Си. Первое перевод терминала в неканонический режим
работы я уже описывала вот здесь
Но сколько я не гуглила не смогла найти подсказку как мне вводить символы разной длинны
в терминале. Пришлось засучить рукава, обложится подсказками и приняться самой за дело.
Первое что я не забыла это то что в библиотеке управления терминалом termios есть флаги
которые отвечают за размер буфера в неканоническом режиме и флага ожидания с момента
первого введенного байта. Библитеки wchar и wctype любезно предоставили мне функции
по работе со знаками размером в 4 байта и соответствующие к ним типы переменных wchar_t и wint_t.
Префикс 'w' подразумевает слово 'wide' - расширеный. Кирилица состоит из двух байтовых символов.
Но я не стала ограничивать размер вводимых знаков 2 байтами и выбрала буфер ввода размером
в 4 байта, а время ожидания после ввода первого байта определила в долю секунды. Теперь
мой терминальчик может считывать любые символы за раз состоящие от одного байта(аски) до китайских
иероглифов и даже чередовать их ввод. Теперь каждый последующий введенный символ после проверки на
корректность, можно добавлять к предыдущему введенному и в цикле организовать нужный динамический
поиск по базе. Даже закомичу свой кусочек кода :) .

Код: Выделить всё

#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <wctype.h>
#include <wchar.h>
#include <locale.h>
 
struct termios oldt, newt;

int main()
{
        if (! setlocale(LC_ALL, "ru_RU.utf8mb4"))
                puts("error locale"), exit(1);

//      wchar_t wc[80] = L"ща";
//      wint_t ch = L'щ';
        wint_t terminate = L'\n';
        wchar_t wch;
        tcgetattr(0, &oldt);
        newt = oldt;
        newt.c_lflag &= ~(ICANON|ECHO);
        newt.c_cc[VMIN] = 4;
        newt.c_cc[VTIME] = 1;
        tcsetattr(0, TCSANOW, &newt);
        while((wch = getwchar()) != terminate)
        {
                putwchar(wch);
                putwchar(terminate);
//              wprintf(L"%lc %d %zd\n", wch, wch, sizeof(wch));
        }   
        tcsetattr(0, TCSANOW, &oldt);
        return 0;
}
[album]440[/album]
"I invented the term Object-Oriented and I can tell you I did not have C++ in mind." - Alan Kay
Olej

Re: utf-8 в Си

Сообщение Olej »

nezabudka писал(а):Библитеки wchar и wctype любезно предоставили мне функции
по работе со знаками размером в 4 байта и соответствующие к ним типы переменных wchar_t и wint_t.
Префикс 'w' подразумевает слово 'wide' - расширеный. Кирилица состоит из двух байтовых символов.
Но я не стала ограничивать размер вводимых знаков 2 байтами и выбрала буфер ввода размером
в 4 байта, а время ожидания после ввода первого байта определила в долю секунды.
Таблицы Unicode для любого символа (английского и китайского) выражается 32-битным значением.
И это и есть wchar_t, который имеет в UNIX/Linux размер 4 байта (не путать с Windows, где wchar_t - это 2 байта, 16 бит).

Но таблицы Unicode - это абстракция. А для представления этих значений нужно их как-то кодировать.
И для этого есть UTF-32 (это чисто значения Unicode и wchar_t POSIX), UTF-16 (и wchar_t Windows ... это нам не интересно) и UTF-8 (байтное кодирование переменной длины, которое было придумано для ОС Plan 9).
Любой существующий символ кодируется в UTF-8 от 1-го до 6-ти байт (char).

В C есть
- байтовый тип char + набор операций вида str*() : strlen() и т.д. + puts(), gets() и т.д.
- тип широких символов wchar_t + набор операций (полностью эквивалентный str*()) wcs*() : wcslen() + fputws(), printf() формат %ls и т.д.
- набор функций преобразования от мультибайтных последовательностей char (UTF-8) в wchar_t и наоборот - функции вида mb*(): mbtowc() и др.

Именно с строками wchar_t вы можете правильно делать все операции с русским текстом: поиск, замена и т.д.

По этой ... малоизученной :shock: :D теме - локализации в C, можете найти кое-что полезное здесь: локализация строк в C-коде
Но сколько я не гуглила не смогла найти подсказку как мне вводить символы разной длинны
в терминале.
А не нужно мучить терминал ;)
- читайте просто в строку char[], побайтно...
- преобразовывайте считанное с помощью функций mb*() в wchar_t[]
- работайте безбоязненно с wchar_t[] так, как это в книжках описывают для char[]

Альтернативный вариант:
- fgetwc(), getwc(), fgetws(), fputws() и др. подобные (см. <wchar.h>) для непосредственного ввода/вывода wchar_t[]
- а дальше всё как в предыдущем случае ;) ... wcscmp(), wcslen(), wcsstr() и т.д.
Olej

Re: utf-8 в Си

Сообщение Olej »

nezabudka писал(а):Задача тривиальная. Имеется
база сотрудников нашего управления. И нужно на начальном этапе организовать
поиск в базе по фамилии.
Напишите консольное приложение на Go - там у вас не будет проблем ни с UTF-8, ни с русскими символами, ни с операциями со строками...
Olej

Re: utf-8 в Си

Сообщение Olej »

Olej писал(а): - а дальше всё как в предыдущем случае ;) ... wcscmp(), wcslen(), wcsstr() и т.д.
Во всём этом кине :D , забегая вперёд, предупрежу вас об одном очень не очевидном эффекте - и в C и в C++:
- в выходной поток SYSOUT, SYSERR (терминал) вы можете писать, в принципе, как в поток char (printf("%s")) так и поток wchar_t (printf("%ls"))...
- но как только вы хоть один раз запишите в wchar_t поток строку char, то уже поток вывода wchar_t вы разрушите ...
- и последующие printf("%ls") будут выводить ерунду...

Исправить это можно только переоткрыв поток, вот так:

Код: Выделить всё

stdout = freopen( "/dev/stdout", "w", stdout );
P.S. Вот этого вы уж точно не нагуглите нигде! :o
См. http://rus-linux.net/forum/viewtopic.ph ... 066#p14069
Аватара пользователя
nezabudka
Местный говорун
Местный говорун
Сообщения: 618
Зарегистрирован: 18 апр 2015, 06:13
Откуда: Ростов на Дону

Re: utf-8 в Си

Сообщение nezabudka »

Olej писал(а):Напишите консольное приложение на Go - там у вас не будет проблем ни с UTF-8, ни с русскими символами, ни с операциями со строками...
И было такое желание и именно на go. Но боюсь каши в голове. Пусть пока подождет. Мне ж в принципе не приложение нужно, а канитель :D
"I invented the term Object-Oriented and I can tell you I did not have C++ in mind." - Alan Kay
Аватара пользователя
nezabudka
Местный говорун
Местный говорун
Сообщения: 618
Зарегистрирован: 18 апр 2015, 06:13
Откуда: Ростов на Дону

Re: utf-8 в Си

Сообщение nezabudka »

Olej писал(а):...предупрежу вас об одном очень не очевидном эффекте...
Тото я и думаю что некоторые забеги по непонятной для меня причине заканчивались неудачно. За это вам отдельное мерси :!:
"I invented the term Object-Oriented and I can tell you I did not have C++ in mind." - Alan Kay
Olej

Re: utf-8 в Си

Сообщение Olej »

nezabudka писал(а):Тото я и думаю что некоторые забеги по непонятной для меня причине заканчивались неудачно. За это вам отдельное мерси :!:
Olej писал(а):По этой ... малоизученной :shock: :D теме - локализации в C
Обратите внимание, что эта тема - работа с wchar_t, UTF-8 - действительно почти не отражена в публикациях по языкам C и C++.
На то есть несколько причин:
- сам тип wchar_t появился в стандарте C89, но в полной мере, с API поддержки и т.п. - только в стандарте C99 ... т.е. относительно недавно (по крайней мере в сравнении с 45-летней историей C)
- и, конечно, не может даже упоминаться в классической литературе по C: K&R и т.п.
- более поздние книги и учебники по C, переводные, тоже практически обходят эту тему стороной ... их англоязычным авторам она "до фени", оно им не актуально ... да они и сами этой стороны не знают :D
- отечественные, русскоязычные учебники (а здесь я встречал только учебные книги по C, для студентов университетов, например ... кто же станет писать "не-учебник" по столь древнему языку?) - здесь авторы, не являющиеся практиками, сами тоже, главным образом, переписывают из англоязычных изданий ... ну, придумают десяток своих примеров, а раз там этого нет, то его и вообще нет в природе. :shock:

P.S. Такая же история в C, например, с комплексными числами как типом данных - основа всех расчётов в электротехнике, радиотехнике, 2D-геометрии векторной и др. - этот тип присутствует во всю ширь в C99 со всеми операциями и API ... но умельцы нородят свои strucr { double re, im; } :D
По некоторым новым вещам в C может оказаться полезным: Язык C: заметки на полях
Olej

Re: utf-8 в Си

Сообщение Olej »

Olej писал(а):Обратите внимание, что эта тема - работа с wchar_t, UTF-8 - действительно почти не отражена в публикациях по языкам C и C++.
Хорошо проработанный материал по локализации в C & C++ мог бы стать отличным содержанием отдельной книжки русскоязычной.
Это было бы куда полезнее, чем переливать из пустого в порожнее, и издавать ещё одно учебной издание "про язык C".

P.S. Я говорю "C & C++" сознательно, потому что, что бы там не верещали умники, C++ это надстройка над C, и база у них общая.
Olej

Re: utf-8 в Си

Сообщение Olej »

Olej писал(а): По некоторым новым вещам в C может оказаться полезным: Язык C: заметки на полях
P.P.S. И ещё вот здесь можете найти кой-чего любопытного в тему: Задачи по программированию на языке C, обновление
Olej

Re: utf-8 в Си

Сообщение Olej »

Olej писал(а): Хорошо проработанный материал по локализации в C & C++ мог бы стать отличным содержанием отдельной книжки русскоязычной.
Это было бы куда полезнее, чем переливать из пустого в порожнее, и издавать ещё одно учебной издание "про язык C".

P.S. Я говорю "C & C++" сознательно, потому что, что бы там не верещали умники, C++ это надстройка над C, и база у них общая.
Чтоб не пустословить, я записал то, что знаю по локализации, Unicode, UTF-8 с C/C++ ... ну, книга, далеко не книга, но так ... заметки для памятки.
Это для затравки, то что есть пока...

А дальнейшее развитие текста см. здесь: локализация строк в C-коде.
nezabudka писал(а):Применение шаблонов регулярных выражений это следующий этап и забегать вперед не стану.
А это уже следующий этап в эту задачу: регулярные выражения, но с локализованными (русскоязычными) строками (wchar_t[ ]).
Хотя ... в C работа с регулярными выражениями - это исключительно через задницу. :shock:
Или использовать C++ ? ... или библиотеку a'la Perl регулярных выражений: <pcre.h> + libpcre.so ?
Вложения
localiz_05.tgz
(3.98 КБ) 363 скачивания
localiz_05.odt
(49.61 КБ) 352 скачивания
Ответить

Вернуться в «C/C++»