Страницы

Поиск по вопросам

пятница, 13 декабря 2019 г.

Как стандартными способами c++11 записать файл в utf-8

#cpp #linux #utf_8 #cpp11 #потоки_данных


А именно использую ofstream и в самом файле записывается русскими буками хорошо,
а вот с названием документа проблемы. Что только не пробовал, название файла получается
что-то вроде такого �.txt (неверная кодировка)



Может я не совсем правильно задал вопрос, мне нужно чтобы программа сохраняла txt
файл с названиями аа.txt аб.txt ав.txt - ... - яя.txt

Кратко расскажу суть программы: Есть словарь слов, расположенный в алфавитном порядке,
программа должна разбить этот словарь по 33*33 документам (Минус 3*32, нет слов начинающихся
с ь,ы,ъ). Документ аб.txt будет иметь все слова начинающиеся с аб...

Запись в файлы корректная, единственное, что названия файлов неправильные

Вот моя функция main():

int main() {
    if (rfile.is_open()) {
        while (getline(rfile, line)) {
            string first, second;
            try {
                first = line[0];
                second = line[1];
            }catch (...) {
                continue;
            }
            if (first == " " || first == "." || first == "-" || first == "|" || first
== "," ||
                second == " " || second == "|" || second == "-" || second == "."
|| second == ",")
                continue;
            string wfilename = first + second + ".txt";
            ofstream wfile;
            wfile.open(wdirectory + wfilename, ios_base::app);
            if (wfile.is_open())
                wfile << line;
            wfile.close();
        }
        rfile.close();
    }
    else cout << "Unable to open file" << endl;

    return 0;
}


Система Linux mint x64



Решение найдено! Я брал первые две буквы строки и использовал их для составления
названия. Чтобы все корректно работало, нужно было конвертировать исходный файл в utf-8.
На linux эта команда выглядит как iconv -f windows-1251 < /home/user/filename.txt
> /home/user/newEncodedFilename.txt
Знаки < и > обязательны. Далее уже использовать новый файл. Спасибо sercxjo
    


Ответы

Ответ 1



Русские буквы в utf-8 обычно занимают 2 байта. Выбирая первые два байта из строки вы скорее всего получите только одну русскую букву, но возможно если первый из них другой символ или длина utf-8-представления символа более 2 байт, некорректно прерывается последовательность utf-8 кодировки. Для первого байта последовательности (x&192)==192, для остальных (x&192)==128. По этим признакам можно вырезать первую и вторую буквы (точнее в первом байте указывается длина последовательности в единичной системе исчисления, но будем надеяться на правильность исходных данных). Таким образом, найти длину символа поможет функция: int wlen(const string &x, int start) { if(x[start]==0) return 0; if((x[start]&192)!=192) return 1; int i=1; while((x[start+i]&192)==128) i++; return i; } Теперь остаётся заменить получение первого и второго символов строки: first = line.substr(0, wlen(line, 0)); second = line.substr(first.size(), wlen(line, first.size())); Ну и далее можно добавить анализ, что first.size()==0 || second.size()==0 Из беседы в чате выяснилось, что исходный файл в кодировке windows-1251. Чтобы привести его в кодировку принятую в Linux Mint можно использовать команду iconv: iconv -f windows-1251 < исходный_файл > новый_файл Если требуется включить перекодировку в саму программу, можно использовать libiconv пример.

Ответ 2



Проверяйте вашу системную локаль и что именно содержится в файлах. Ибо всё прекрасно работает: 1: $ locale LANG=ru_RU.UTF-8 LANGUAGE= LC_CTYPE="ru_RU.UTF-8" LC_NUMERIC="ru_RU.UTF-8" LC_TIME="ru_RU.UTF-8" LC_COLLATE="ru_RU.UTF-8" LC_MONETARY="ru_RU.UTF-8" LC_MESSAGES="ru_RU.UTF-8" LC_PAPER="ru_RU.UTF-8" LC_NAME="ru_RU.UTF-8" LC_ADDRESS="ru_RU.UTF-8" LC_TELEPHONE="ru_RU.UTF-8" LC_MEASUREMENT="ru_RU.UTF-8" LC_IDENTIFICATION="ru_RU.UTF-8" LC_ALL= $ ls ф* ффф.текст $ cat ффф.текст ффф.результат $ ./a.out ффф.результат $ ls ф* ффф.результат ффф.текст 2: #include #include #include int main() { std::ifstream rfile; rfile.open( "ффф.текст" ); std::string line; getline(rfile, line); rfile.close(); std::cout << line << std::endl; std::ofstream wfile; wfile.open( line.c_str() ); wfile.close(); }

Комментариев нет:

Отправить комментарий