Linux GCC, класс std::string и utf-8 (Странные ошибки при доступе к отдельным символам)

Модератор: Модераторы разделов

Аватара пользователя
0xDEAD
Сообщения: 54
ОС: Ubuntu Linux

Linux GCC, класс std::string и utf-8

Сообщение 0xDEAD »

При доступе к отдельным символом строки, содержащей русские символы, возвращаются какие-то странные символы.
Как это можно обойти, все равно использую utf-8?

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

// Этот файл был введен в кодировке utf-8 (использовался vim с параметрами по умолчанию).
#include<iostream>
#include<string>
using namespace std;

int main()
{
        string   testStr = "АБВГ...";

        /* Вывод производится столь извращенным способом для того, чтобы
         * показать получение всего одного русского символа.
         * У меня вывод происходит квадратиками, вывод же строки
         * полностью происходит нормально. Получение отдельного символа
         * необходимо для написания руссифицированной функции
         *  string tolower(string upStr)*/
        for (int i=1; i < testStr.length(); i++)
                cout << testStr[i] << endl;

        return 0;
}
Спасибо сказали:
v04bvs
Сообщения: 636
ОС: Debian GNU/Linux

Re: Linux GCC, класс std::string и utf-8

Сообщение v04bvs »

Нормального способа в рамках C++, афаик нет. Лучше всего использовать какую-нибудь стороннюю библиотеку, например в Qt очень хорошая поддержка юникода.
Спасибо сказали:
Аватара пользователя
0xDEAD
Сообщения: 54
ОС: Ubuntu Linux

Re: Linux GCC, класс std::string и utf-8

Сообщение 0xDEAD »

Спасибо, а то я все пытался с чистым С++ мучиться!
Спасибо сказали:
watashiwa_daredeska
Бывший модератор
Сообщения: 4038
Статус: Искусственный интеллект (pre-alpha)
ОС: Debian GNU/Linux

Re: Linux GCC, класс std::string и utf-8

Сообщение watashiwa_daredeska »

0xDEAD писал(а):
15.07.2006 22:36
При доступе к отдельным символом строки, содержащей русские символы, возвращаются какие-то странные символы.
Как это можно обойти, все равно использую utf-8?


UTF-8 --- кодировка с переменной длиной символа (1-6 байт). Русские буквы в UTF-8 занимают 2 байта. Поэтому приведенный код и не работает. См. unicode.org, RFC3629.

Если есть намерение работать с Unicode, то лучше всего использовать внутри wchar_t и какую-нибудь библиотеку, типа iconv, для конвертации из/в локали при вводе/выводе.
Спасибо сказали:
Аватара пользователя
oav
Бывший модератор
Сообщения: 296

Re: Linux GCC, класс std::string и utf-8

Сообщение oav »

watashiwa_daredeska писал(а):
16.07.2006 21:59
0xDEAD писал(а):
15.07.2006 22:36

При доступе к отдельным символом строки, содержащей русские символы, возвращаются какие-то странные символы.
Как это можно обойти, все равно использую utf-8?


UTF-8 --- кодировка с переменной длиной символа (1-6 байт). Русские буквы в UTF-8 занимают 2 байта. Поэтому приведенный код и не работает. См. unicode.org, RFC3629.

Если есть намерение работать с Unicode, то лучше всего использовать внутри wchar_t и какую-нибудь библиотеку, типа iconv, для конвертации из/в локали при вводе/выводе.

Полностью поддерживаю высказывание, но ради так сказать справедливости можно еще так:

std::wstring = L"Привет";
Спасибо сказали:
Аватара пользователя
elide
Бывший модератор
Сообщения: 2421
Статус: Übermensch
ОС: лялих

Re: Linux GCC, класс std::string и utf-8

Сообщение elide »

я раньше никогда не сталкивался с необходимостью поддержки многобайтовых кодировок, а встретив эту тему заинтересовался. и, столкнувшись в первой же тестовой программе с пробоемой вывода wstring в файл, нашел небольшую статейку про upgrading an STL-based application to use Unicode. после чего, мне захотелось убежать далеко-далеко, зарыться глубоко-глубоко и сидеть тихо-тихо, чтоб это всё меня никогда не нашло.....
слава роботам!
Спасибо сказали:
Аватара пользователя
oav
Бывший модератор
Сообщения: 296

Re: Linux GCC, класс std::string и utf-8

Сообщение oav »

elide писал(а):
17.07.2006 14:49
я раньше никогда не сталкивался с необходимостью поддержки многобайтовых кодировок, а встретив эту тему заинтересовался. и, столкнувшись в первой же тестовой программе с пробоемой вывода wstring в файл, нашел небольшую статейку про upgrading an STL-based application to use Unicode. после чего, мне захотелось убежать далеко-далеко, зарыться глубоко-глубоко и сидеть тихо-тихо, чтоб это всё меня никогда не нашло.....

У меня в предыдущем проекте была ситуация несколько сложнее чем Unicode - а именно multibyte. Весь STL пришлось выкидывать, boost::filesystem выкидывать, boost::spirit нагибать таааким раком, что мама не горюй. И вообще, вопросы локализации приложений, особенно с GUI - есть большой гимор и реально сложная техн. задача. Опыт получил шикарный.
Спасибо сказали:
gury
Сообщения: 2
ОС: openSuse 12.3

Re: Linux GCC, класс std::string и utf-8

Сообщение gury »

0xDEAD писал(а):
15.07.2006 22:36
При доступе к отдельным символом строки, содержащей русские символы, возвращаются какие-то странные символы.
Как это можно обойти, все равно использую utf-8?

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

// Этот файл был введен в кодировке utf-8 (использовался vim с параметрами по умолчанию).
#include<iostream>
#include<string>
using namespace std;

int main()
{
        string   testStr = "АБВГ...";

        /* Вывод производится столь извращенным способом для того, чтобы
         * показать получение всего одного русского символа.
         * У меня вывод происходит квадратиками, вывод же строки
         * полностью происходит нормально. Получение отдельного символа
         * необходимо для написания руссифицированной функции
         *  string tolower(string upStr)*/
        for (int i=1; i < testStr.length(); i++)
                cout << testStr[i] << endl;

        return 0;
}

Вот у меня была обратная проблема... Всё вводилось в UTF-8 и работало. Если работать только с английским текстом. то пофиг. UTF-8 эквивалентна ASCII тексту с первой половиной кодировки! У неё абсолютная совместимость Но если начинаешь работать с русским или другим языком то тут-то и начинаются чудеса в решете... Каждый русский символ всегда занимает 2 байта и с этим ничего не попишешь, а английский 1 байт. И если в строке есть и те и другие символы, то строка будет что-то среднее. Вобщем это мультибайтовая строка... К чему такое расточительство неясно!!! Тем более в обычной ASCII все символы прекрасно помещаются в 1 байт и русские, и английские!!!! Вобщем я всё перенастроил на KOI8-R и нету проблем... Во-первых посмотрите какая у вас системная кодировка... Установите UTF-8(у меня она стоит). К сожалению я не могу ускбя это поменять иначе многие хэлпа отвалятся или надо будет искать тексты с другой кодировкой. Во вторых если вы пользуетесь konsole, а это обычно так, то посмотрите какая там кодировка. Если у вас системная UTF-8, то как правило все программы работают в этой кодировке! Но это повлияет на ввод комманд. На редактор Vim файл .vimrc там надо настроить кодировки. Там же настраивается и gvim кстати. Настройте строку подсказки чтобы она показывала в какой кодировке отображается текст и перекодируется ли он... Т.е. Vim имеет особенность перекодировать файл. Несмотря на все настройки он сабака всё равно открывает новый файл в системной кодировке. Но если вы наберёте русский текст и сохраните, то он сохранит его в нужной кодировке. Но это только новый файл... Старые файлы он будет перекодировать и редактировать в настроенной вами кодировке, а сохранять в его старой кодировке. Как обойти такое поведение я не знаю, но это факт. Чтобы вы не делали, если изначально установилась какая-то кодировка то изменить её Vim-ом вы не сможете. Хотя редактироваться и отображаться при этом он может в любой кодировке. Вот так вот. Я лично взял и перекодировал все файлы из UTF-8 в КOI8-R с помощью другого редактора KWrite. И теперь всё нормально. Но учтите, если вы пользуетесь скажем gcc, то все сообщения он выдаёт тоже в системной кодировке. И если вы хотите это изменить, то вам придётся либо задать переменную окружения LANG при вызове псс или её же в Makefile. Я делаю второй вариант для установки KOI8-R. Даже для вызова справки man страниц приходится задавать кодировку... Вобщем я больше склоняюсь к мысли, что проще поменять системную кодировку, чем так мучатся... Хотя это тоже вызовет немалые проблемы.
Спасибо сказали:
gury
Сообщения: 2
ОС: openSuse 12.3

Re: Linux GCC, класс std::string и utf-8

Сообщение gury »

elide писал(а):
17.07.2006 14:49
я раньше никогда не сталкивался с необходимостью поддержки многобайтовых кодировок, а встретив эту тему заинтересовался. и, столкнувшись в первой же тестовой программе с пробоемой вывода wstring в файл, нашел небольшую статейку про <noindex>upgrading an STL-based application to use Unicode.</noindex> после чего, мне захотелось убежать далеко-далеко, зарыться глубоко-глубоко и сидеть тихо-тихо, чтоб это всё меня никогда не нашло.....

Вот-вот!!! А главное нет смысла... Обычная ASCII строка делает то же самое и работает быстрее и без проблем. К тому же занимает в 2 раза меньше места. Вы ничего не выигрываете от применения UTF-8... только геморрой приобретаете себе на голову! Но если у вас нету выхода то мой вам совет ,считайте её как ASCII и тут же преобразуйте в нормальный unicode Вы даже не потеряете в длине. Она будет такая же... а работать с Unicode на порядок проще!!! Если у вас ещё есть С++11 то там есть конверторы. Если нет, то в POSIX есть функции преобразования мультибайтовых строк в юникод. Вот ими и надо воспользоваться. А ещё лучше избегайте мультибайтовых кодировок. Эффкт от них только если вы используете какой-нибудь традиционный(даеж не симрл) китайский или ещё какой нибудь иероглифический язык. Собственно именно для этого они и были предназначены. но я не думаю,что Вам это хоть когда нибудь понадобится. К тому же придётся учить китайский... Вобщем жуть!!!
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: Linux GCC, класс std::string и utf-8

Сообщение drBatty »

gury
простите, но вы не правы: благодаря UTF-8 в GNU Linux решена проблема ВСЕХ языков, в т.ч. и русского. При этом сохранена поддержка также и ASCIIZ.

gury писал(а):
28.07.2013 01:00
Каждый русский символ всегда занимает 2 байта и с этим ничего не попишешь, а английский 1 байт. И если в строке есть и те и другие символы, то строка будет что-то среднее. Вобщем это мультибайтовая строка... К чему такое расточительство неясно!!!

потому-что в мире не только русский и английский. Посмотрите на венду -- она бывает только русско-английская, и придётся вам делать по отдельной программе к каждому языку. Обычно этим особо не заморачиваются, и по той причине лучше использовать англ. версию, чем уродскую "русевекакацию". С Linux такой проблемы нет. К тому-же, везде можно использовать любые буквы, какие вы хотите. И даже не буквы, типа ☣.

Что касается C, то проблема лишь в индексации по буквам, а я не очень представляю, ГДЕ её надо использовать, кроме разве-что хэлловорлдов? Ну если так уж НАДО, сделайте свой шестибайтовый тип...
gury писал(а):
28.07.2013 01:00
И если вы хотите это изменить, то вам придётся либо задать переменную окружения LANG при вызове псс или её же в Makefile.

поставьте её в ~/.bashrc, или даже в /etc/profile, в чём проблема?
gury писал(а):
28.07.2013 01:09
Вот-вот!!! А главное нет смысла... Обычная ASCII строка делает то же самое и работает быстрее

тащем-то уже 7 лет прошло... Может пора вылезать из криокамеры?
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
Rootlexx
Бывший модератор
Сообщения: 4471
Статус: GNU generation
ОС: Debian GNU/Linux

Re: Linux GCC, класс std::string и utf-8

Сообщение Rootlexx »

drBatty писал(а):
28.07.2013 07:04
Что касается C, то проблема лишь в индексации по буквам, а я не очень представляю, ГДЕ её надо использовать, кроме разве-что хэлловорлдов? Ну если так уж НАДО, сделайте свой шестибайтовый тип...

Да даже делать ничего не надо: есть тип wchar_t и набор функций для работы с ним и конвертирования. См. https://en.wikipedia.org/wiki/C_string_handling.
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: Linux GCC, класс std::string и utf-8

Сообщение drBatty »

Rootlexx писал(а):
28.07.2013 14:24
Да даже делать ничего не надо: есть тип wchar_t

есть конечно. Только это не нужно обычно.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали: