Mail.ruПочтаМой МирОдноклассникиВКонтактеИгрыЗнакомстваНовостиКалендарьОблакоЗаметкиВсе проекты

Как узнать количество символов в UTF8 массиве?(Си)

kh fjkg Знаток (328), закрыт 3 года назад
Char arr[]={"Кириллица Latin"};
Я пользовался всегда UTF16 широкими символами, хочу перейти на UTF8.
В UTF8 количество Байт на символ различаются, поэтому количество Байт в массиве не соответствует количеству символов в массиве.
Есть ли простой способ узнать количество символов в UTF8 массиве?

И ещё как можно например сравнить элемент UTF8 массива с чем либо?
Например if(arr[0]==L'Я')
Так ведь не получится, потому что буква Я занимает 2 Байта.
Мне кажется или UTF8 очень неудобный?
Лучший ответ
Дед Мазай Гений (58129) 3 года назад
Есть разные подходы.
1. Выполнять обработку строк в UTF-16 или (лучше) в UTF-32. Если данные в UTF-8, они преобразуются в одну из этих кодировок. В UTF-16 один символ может кодироваться парой кодов. В UTF-32 такого нет.
2. Использовать специальные функции для работы с UTF-8, или самому написать соответствующий код. В этом случае русская буква - это не символ, а строка.
Для того чтоб пробежаться по строке, ты привык использовать инкремент индекса. При работе с UTF-8 последовательно определяют длину каждого символа, так перебирают символы строки.

Функция mblen возвращает длину символа в байтах
https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/mbclen-mblen-mblen-l
Пишут, что mblen может возвращать значение до 3. Это странно, поскольку в UTF-8 символ может кодироваться 4 байтами.
kh fjkgЗнаток (328) 3 года назад
>>Функция mblen возвращает длину символа в байтах
Пишут что для mblen нужна setlocale, я её вставил тоже.
mblen получает в качестве параметра массив и возвращает количество Байт на 1 символ??
А если в массиве разные типы символов с разным количеством Байт на символ?

Н всё равно неправильно выводит количество Байт даже только для кириллицы у меня. Выводит 1 Байт для кириллицы. Неправильно. Должно быть 2 Байта на символ.
Кодировку и Байты я проверял.
Может что то не так делаю?

setlocale(LC_ALL, ".1251");
char arr[]={"Кириллица Latin"};
printf("%d\n", mblen(arr, 2));
Дед Мазай Гений (58129) kh fjkg, mblen возвращает длину одного символа (того, на начало которого указывает указатель)
kh fjkgЗнаток (328) 3 года назад
>>1. Выполнять обработку строк в UTF-16 или (лучше) в UTF-32.
Для этих типов куча своих аналогов функций и многие из них не кроссплатформенные.
kh fjkgЗнаток (328) 3 года назад
>>В UTF-32 такого нет.
32 бита насимвол слишком много
kh fjkgЗнаток (328) 3 года назад
>>При работе с UTF-8 последовательно определяют длину каждого символа, так перебирают символы строки.
Получается вместо этого if(arr[0]==L'Я') надо писать код на 100 строк?
Дед Мазай Гений (58129) kh fjkg, я никогда не работал со строками в UTF-8 (кроме их преобразования в широкие символы). Насколько я знаю, это удобно сделано в Rust.
kh fjkgЗнаток (328) 3 года назад
>>mblen возвращает длину одного символа (того, на начало которого указывает указатель)
Да, я догадался, но у меня 1 выводит на кириллицу.
А онлайн компилятор 2 Байта выводит https://onlinegdb.com/sFoG9WHUt
У меня UTF8 массив
Дед Мазай Гений (58129) > У меня UTF8 массив Откуда это видно?
kh fjkgЗнаток (328) 3 года назад
208 154 Это UTF8 кодировка для символа К
У меня UTF8, я её выставлял
kh fjkgЗнаток (328) 3 года назад
>>Откуда это видно?
Например ко коду, который получается у символа К.
Только в UTF8 такой код у этого символа
Дед Мазай Гений (58129) kh fjkg, да, действительно не работает. Я не знаю, почему так. В gcc на Windows тоже не работает.
kh fjkgЗнаток (328) 3 года назад
>>так тоже работает setlocale(LC_CTYPE, ".utf8");
В Visual Studio кодировка в utf8 переводится, а в других компиляторах видимо нет.

char*p=setlocale(LC_ALL, ".utf8");
printf("%s\n", p);
kh fjkgЗнаток (328) 3 года назад
Здесь пишут https://github.com/MicrosoftDocs/cpp-docs/issues/1469 что поддержка utf8 локали была введена в Visual Studio.
Значит видимо раньше этой поддержки не было. Может в других компиляторах её до сих пор и нет.
Пост 2019 года.
Дед Мазай Гений (58129) kh fjkg, ты путаешь Visual Studio (среда разработки), компилятор и библиотеки. Visual Studio (как текстовый редактор) уже давно поддерживает UTF-8. Поддержка UTF-8 в функции MultiByteToWideChar тоже есть очень давно. В статье по твоей ссылке упоминаются VS2015 и VS2017. В компиляторе GCC из MinGW, которым я пользуюсь, непонятно как указать кодировку в setlocale. Это проблема не компилятора, а библиотек или самой системы MinGW. Поэтому мне нравится функция MultiByteToWideChar: она не зависит от библиотек компилятора.
kh fjkgЗнаток (328) 3 года назад
Есть функция для побайтового копирования или конвертирования в широкие символы из utf8?
То есть из utf8 массива побайтово копировать указанное количество Байт.
Это бы сильно облегчило работу с utf8 массивом.
Дед Мазай Гений (58129) kh fjkg, конечно есть mbstowcs - стандартная функция mbstowcs_s - версия с улучшенной безопасностью Сначала надо выбрать кодировку setlocale(LC_CTYPE, ".65001"); Есть ещё другие функции. См. документацию. MultiByteToWideChar - функция Windows API. Я пользовался только ей. Конечно широкие символы удобней чем UTF-8, особенно на Windows, где UTF-16LE родная кодировка ОС.
kh fjkgЗнаток (328) 3 года назад
Жаль это функция не кроссплатформенная, мне она тоже нравится.
Но всё же с ней не всё так хорошо. Если копируешь часть utf8 массива, а не весь, то может вывестись мусор в конце.
kh fjkgЗнаток (328) 3 года назад
>>Visual Studio (как текстовый редактор) уже давно поддерживает UTF-8.
https://docs.microsoft.com/ru-ru/cpp/c-runtime-library/reference/setlocale-wsetlocale?view=msvc-170
начиная с версии Windows 10 1803 (10.0.17134.0), универсальная среда выполнения C поддерживает использование кодовой страницы UTF-8. Это означает, что char строки, передаваемые в функции среды выполнения C, будут ждать строк в кодировке UTF-8. Чтобы включить режим UTF-8, используйте ".UTF8" в качестве кодовой страницы при использовании setlocale . например, setlocale(LC_ALL, ".UTF8") будет использовать текущую стандартную кодовую страницу ANSI Windows (ACP) для языкового стандарта и кодировку UTF-8 для кодовой страницы.
Остальные ответы
Животное Мудрец (16231) 3 года назад
Можно сделать по-хитрому! Смотри как. Чтобы это что-либо было тоже в UTF-8! Можно заставить работать Студию в UTF-8, есть специальные настройки для редактора и компилятора. Компилер ресурсов тоже прекрасно работает с UTF-8, главное включить соответствующую опцию. (Про Линукс объяснять не буду, там UTF-8 из коробки.) Вот и всё. БААМ, и в программе и в тексте у тебя везде UTF-8, и тебе тогда нужно просто заюзать стандартную memcmp(). Единственная проблема: узнать длинну символа. Тебе нужно будет написать свою функцию для этого. (смотри Википедию) А на основе её, ещё функцию длины строки. И на 99% это покроет все варианты. За исключением лексики, таких, как: tolower(), toupper() и т. д. (Хотя, в десятке могли поддержку уже добавить, я не слежу за этим...)
Похожие вопросы