首页 > 解决方案 > C++ 正确使用 cout wcout ifstream 读取带有重音字符的文本文件

问题描述

我想在 Ubuntu 20.04 上读取一个 txt 编码的 UTF8 文件。

我在 wcout cout 和 ifstream 中添加了一个语言环境 fr_FR.UTF-8。

我在想只添加语言环境就足够了。

输出给出了这个:

在此处输入图像描述

这是我的代码

...
#include <iostream>
#include <fstream>
#include <ctime>
#include <cstdlib>
#include <vector>
#include <string>
#include <locale>
#include <codecvt>
    
int main(int argc, char** argv){
    
    int nbreLigne;
    std::vector<std::wstring> dico;
    std::string path("liste_test.txt");
    std::wstring ligne;
    
    std::locale loc("fr_FR.UTF-8");
    std::cout.imbue(loc);
    std::wcout.imbue(loc);
    std::wifstream file(path.c_str(), std::ios::in);
    file.imbue(loc);
    std::cout << "Path = " << path << std::endl;
    std::cout << "1- locale wifstream : " << file.getloc().name() << std::endl;
    std::cout << "2- locale wcout : " << std::wcout.getloc().name() << std::endl;
    std::cout << "3- locale cout : " <<  std::cout.getloc().name() << std::endl;
    /* Pas d'erreur de compile mais ne semble pas avoir d'effet 
    file.imbue(std::locale(file.getloc(), new std::codecvt_utf8<wchar_t, 0x10ffff, std::consume_header>));
    std::cout << "1- Variable de localisation : " << file.getloc().name();
    */

    if (file){
        
        //compte les lignes      
        while (std::getline(file, ligne)){
            nbreLigne++;
            dico.push_back(ligne);

            /*
            Erreur de segmentation (core dumped) si cette ligne est activée
            std::wcout << dico[nbreLigne] << std::endl; 
            */
        }
    
        std::cout << "Total lines number = " << nbreLigne << std::endl;
        
    }
    else{
        std::cout << "ERREUR: Impossible d'ouvrir le fichier." << std::endl;
    }

    std::cout << "-------------------" << std::endl;
    std::cout << "Lecture de la variable dico" << std::endl;
    std::cout << std::endl;
    for(int i = 0; i < nbreLigne; i++){
       std::wcout << dico[i] << std::endl;
    }
    
...

如何正确使用带有 cout、wcout 和 ifstream 的语言环境?

标签: c++ubuntulocaleifstream

解决方案


简单地说,在 C++和大多数编程语言中没有通用的方法来处理重音字符。只有 ASCII几乎是通用的,并且只涵盖英文字符。随着时间的推移,处理语言特定字符的多种解决方案已经从Windows 代码页UTF-8槽宽字符std::wcout适用于那些宽字符)。

您的问题不是您的程序(除非它应该只std::cout在这种情况下使用),而是您的字典使用与终端字符集不同的字符集。

解决字符集问题既困难又无聊。在您的情况下,用 UTF-8 手动重写字典或使用iconv(1)是值得的。在实际项目中,您将使用像GNU gettext这样的国际化(i18n) 工具来为您处理这个负担。今天,大多数现代系统都使用 UTF-8。

此外,在 C++ 流上设置区域设置只会更改程序格式值(如<<浮点数时的小数分隔符)的方式,它不能更改控制台区域设置,因为std::cin不一定是终端并且可能非常奇怪。


推荐阅读