URL: https://www.opennet.ru/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID9
Нить номер: 7654
[ Назад ]

Исходное сообщение
"C++ Разбивка строки с кириллицей"

Отправлено Heretic , 17-Окт-08 13:04 
Имеется небольшая программа, которая получает строки из файла и с определенного символа разбивает его выводя на экран, то что, соответственно, разбила. Но вывод у меня получается кривой, например:
�С СПб Мегафон         1:00
Как победить такую проблему? Заранее спасибо.

Код программы и содержимое текстового файлика ниже.


$less ./1.cpp
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
int main() {
    vector<string> v;
    string str_t, str;
    char intchar;
    ifstream in ("1.txt"); //Открываем поток для файла
    while (in.get(intchar)) { //Читаем посимвольно
        if (intchar == '\n') { //Если символ является переводом строки то ..
            v.push_back(str); // добавляем строку в массив
            str.erase(); // отчищаем строку
        } else {
            str += intchar; //иначе добавляем символы в строку
        };
    };
    in.close(); // Заканчиваем работу с файлом
    for (unsigned int i=0; i<v.size(); i++) {
            for (int k=51;k<=103;k++) {
                str_t+=v[i][k];
            };
            cout << str_t << endl;
            str_t.clear();
    };
};

$less ./1.txt
134-65-10  01/09  14:04        8-921-946-19-50  СПС СПб Мегафон         1:00                       1.50
134-65-10  01/09  14:05        8-911-167-24-24  СПС СПб Телеком 21      1:00                       1.50


Содержание

Сообщения в этом обсуждении
"забивка строки с ++"
Отправлено Andrey Mitrofanov , 17-Окт-08 13:27 
>у меня получается кривой, например:
>Как победить такую проблему? Заранее спасибо.

gawk '{print substr($0,51,103-51+1)}' <1.txt

Не за что.
>for (int k=51;k<=103;k++) {
>    str_t+=v[i][k];
>};


"забивка строки с ++"
Отправлено Heretic , 17-Окт-08 13:34 
>>у меня получается кривой, например:
>>Как победить такую проблему? Заранее спасибо.
>
>gawk '{print substr($0,51,103-51+1)}' <1.txt
>
>Не за что.
>>for (int k=51;k<=103;k++) {
>>    str_t+=v[i][k];
>>};

Спасибо за ответ, но мне бы в c++ виде =) ибо там не только, те строки что в примере.


"забивка строки с ++"
Отправлено NuINu , 17-Окт-08 14:32 
>[оверквотинг удален]
>>
>>gawk '{print substr($0,51,103-51+1)}' <1.txt
>>
>>Не за что.
>>>for (int k=51;k<=103;k++) {
>>>    str_t+=v[i][k];
>>>};
>
>Спасибо за ответ, но мне бы в c++ виде =) ибо там
>не только, те строки что в примере.

Чтобы правильно разбивать строки utf8 надо с ним работать как с utf8 а не как с char
вот посмотрите: http://utfcpp.sourceforge.net/


"забивка строки с ++"
Отправлено Heretic , 17-Окт-08 15:13 
>[оверквотинг удален]
>>>>for (int k=51;k<=103;k++) {
>>>>    str_t+=v[i][k];
>>>>};
>>
>>Спасибо за ответ, но мне бы в c++ виде =) ибо там
>>не только, те строки что в примере.
>
>Чтобы правильно разбивать строки utf8 надо с ним работать как с utf8
>а не как с char
>вот посмотрите: http://utfcpp.sourceforge.net/

Спасибо за статью, буду сейчас курить ее.


"забивка строки с ++"
Отправлено Heretic , 17-Окт-08 15:42 
>[оверквотинг удален]
>>>>>};
>>>
>>>Спасибо за ответ, но мне бы в c++ виде =) ибо там
>>>не только, те строки что в примере.
>>
>>Чтобы правильно разбивать строки utf8 надо с ним работать как с utf8
>>а не как с char
>>вот посмотрите: http://utfcpp.sourceforge.net/
>
>Спасибо за статью, буду сейчас курить ее.

Да если перевести как изначально было в CP-1251, то все нормально. Но я не как не могу понять, почему когда выводил всю строку было все ОК, а когда часть не отрабатывало?


"забивка строки с ++"
Отправлено NuINu , 17-Окт-08 16:10 
>[оверквотинг удален]
>>>
>>>Чтобы правильно разбивать строки utf8 надо с ним работать как с utf8
>>>а не как с char
>>>вот посмотрите: http://utfcpp.sourceforge.net/
>>
>>Спасибо за статью, буду сейчас курить ее.
>
>Да если перевести как изначально было в CP-1251, то все нормально. Но
>я не как не могу понять, почему когда выводил всю строку
>было все ОК, а когда часть не отрабатывало?

cp1251 это однобайтовый символ, с ним все будет работать.

чего вам не понятно? вы разбиваете половину символа utf8, из за этого и знак вопроса.
ссылка показывает как я понял библиотеку, которая нормально решает проблемы с утф8, используйте ее.


"забивка строки с ++"
Отправлено vertur , 17-Ноя-08 15:49 
>[оверквотинг удален]
>>>Не за что.
>>>>for (int k=51;k<=103;k++) {
>>>>    str_t+=v[i][k];
>>>>};
>>
>>Спасибо за ответ, но мне бы в c++ виде =) ибо там
>>не только, те строки что в примере.
>
>Чтобы правильно разбивать строки utf8 надо с ним работать как с utf8
>а не как с char

А вот и нифига. Если требуется разбивка на слова (space,comma,semicolon-separated) или разбивка на строки по \n, то никаких дополнительных знаний об том что это кодировка именно utf8 не надо. Просто работаеш как с однобайтной и паришся - в этом и сила utf8.


"забивка строки с ++"
Отправлено Heretic , 17-Ноя-08 17:20 
>[оверквотинг удален]
>>>Спасибо за ответ, но мне бы в c++ виде =) ибо там
>>>не только, те строки что в примере.
>>
>>Чтобы правильно разбивать строки utf8 надо с ним работать как с utf8
>>а не как с char
>
>А вот и нифига. Если требуется разбивка на слова (space,comma,semicolon-separated) или разбивка
>на строки по \n, то никаких дополнительных знаний об том что
>это кодировка именно utf8 не надо. Просто работаеш как с однобайтной
>и паришся - в этом и сила utf8.

Я собственно так и сделал, по " " разбил и не стал заморачиваться.
Спасибо.


"C++ Разбивка строки с кириллицей"
Отправлено vic , 17-Окт-08 14:31 
// как-то так
#include <iostream>
#include <fstream>
#include <string>
#include <vector>

using namespace std; // вообще-то не гуд

// выносим константы из кода
const streamsize SIZE_LINE = 256; // должно существовать ограничение на длину строки, если нет обрабатывать строку тщательнее..
const size_t FIRST_POS = 51;
const size_t LEN_NAME = 103 - 51;

int main()
{
    try
    {
        vector<string> v;

        //char intchar; - имя переменной вводит в конфуз.
        //string str_t; - суффикc _t означает что это некий тип, так принято (pid_t, size_t).

        ifstream in("file.txt");

        // закидываем строки в массив
        char stmp[SIZE_LINE];
        while (in.getline(stmp, SIZE_LINE)) v.push_back(stmp);

        // обходим массив, можно заменить for_each(), но так сейчас нагляднее
        for (vector<string>::iterator it = v.begin(), et = v.end(); it != et; ++it)
        {
            cout << it->substr(FIRST_POS, LEN_NAME) << endl;
        }

        // а вот тут файлег сам закроется када деструктор для in сработает =)
    }
    catch (exception &e) // общий просто чтобы показать что эксепшены надо обрабатывать
    {
        cerr << "Опаньки, эксепшен: " << e.what() << endl;
        return 1;
    }

    // спасибо за внимание =)
    return 0;
}


"C++ Разбивка строки с кириллицей"
Отправлено Heretic , 17-Окт-08 15:12 
>[оверквотинг удален]
>что эксепшены надо обрабатывать
>    {
>        cerr << "Опаньки, эксепшен:
>" << e.what() << endl;
>        return 1;
>    }
>
>    // спасибо за внимание =)
>    return 0;
>}

Спасибо за ответ, ваша программа не заносила в массив строки (во всяком случае у меня) и попробовав убрать цикл, и получить хотя бы одну строку, и разобрать ее я получил следующее:
�С СПб Телеком 21      1:00

То бишь так же как и у меня =(
Есть еще какие идейки.


"C++ Разбивка строки с кириллицей"
Отправлено vic , 17-Окт-08 15:43 
>
>Спасибо за ответ, ваша программа не заносила в массив строки (во всяком
>случае у меня)

это как? система у вас какая?

>одну строку, и разобрать ее я получил следующее:
>�С СПб Телеком 21      1:00

Проблема в первом символе как я понимаю? Так это зависит от локали и кодировки текста в файле. Какие они?


"C++ Разбивка строки с кириллицей"
Отправлено vic , 17-Окт-08 16:49 
>[оверквотинг удален]
>>Спасибо за ответ, ваша программа не заносила в массив строки (во всяком
>>случае у меня)
>
>это как? система у вас какая?
>
>>одну строку, и разобрать ее я получил следующее:
>>�С СПб Телеком 21      1:00
>
>Проблема в первом символе как я понимаю? Так это зависит от локали
>и кодировки текста в файле. Какие они?

Похоже у вас utf-8 в файле, а со строкой вы работаете считая что 1 символ = 1 байту, поэтому ваше начало подстроки (51) некорректно. в utf-8 русские буквы занимают 2 байта.


"C++ Разбивка строки с кириллицей"
Отправлено vic , 17-Окт-08 16:55 
Заменим на работу с вайдами и станет проще:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <locale>
#include <cstdlib>

using namespace std;

// эти параметры надо установить правильными исчисляя в символах, не в байтах.
const size_t FIRST_POS = 52; // ?
const size_t LEN_NAME = 103 - FIRST_POS;

int main()
{
    // устанавливаем локаль
    setlocale(LC_ALL, getenv("LANG"));
    locale loc(getenv("LANG"));

    wcout.imbue(loc); // локаль для потока вывода

    try
    {
        wfstream in("file.txt");
        in.imbue(loc); // локаль для потока ввода

        // закидываем в массив
        vector<wstring> v;
        wstring s;
        while (getline(in, s)) v.push_back(s);

        // выводим
        for (vector<wstring>::iterator it = v.begin(), et = v.end(); it != et; ++it)
        {
            wcout << it->substr(FIRST_POS, LEN_NAME) << endl;
        }
    }
    catch (exception &e)
    {
        wcerr << L"Опаньки эксепшен: " << e.what() << endl;
        return 1;
    }

    return 0;
}


"C++ Разбивка строки с кириллицей"
Отправлено Heretic , 17-Окт-08 17:37 
>[оверквотинг удален]
>    }
>    catch (exception &e)
>    {
>        wcerr << L"Опаньки эксепшен:
>" << e.what() << endl;
>        return 1;
>    }
>
>    return 0;
>}

Спасибо, за помощь. Дальше буду думать уже сам.