为什么 std::getline() 似乎弄乱了重音字符?

Why does std::getline() seem to mess up accented characters?

提问人:thepaqui 提问时间:9/23/2023 最后编辑:thepaqui 更新时间:9/23/2023 访问量:109

问:

我正在尝试在我的 C++20 程序中使用和显示法语重音字符。

但是,使用在文件内部读取似乎会弄乱重音字符,如下所示:std::getline()

#include <locale>
#include <iostream>
#include <fstream>

int main(void)
{
    setlocale(LC_ALL,"");
    std::wifstream  file("test.txt");
    std::wstring    s;
    std::getline(file, s);
    std::wcout << s << std::endl;
    return 0;
}

test.txt 的内容(以 UTF-8 编码):

Salut ! Comment ça va ? éèêëâàäáôûöüùîï

结果:

$>./test
Salut ! Comment ça va ? éèêëâà äáôûöüùîï

但是,当我尝试显示与 相同的文本时,结果没有问题:const std::wstring

#include <locale>
#include <iostream>

int main(void)
{
    setlocale(LC_ALL,"");
    std::wstring    s = L"Salut ! Comment ça va ? éèêëâàäáôûöüùîï";
    std::wcout << s << std::endl;
    return 0;
}

结果:

$>./test
Salut ! Comment ça va ? éèêëâàäáôûöüùîï

使用使问题变得更好,因为以前甚至第二个示例都不起作用,但似乎有一个问题,我不明白。setlocale(LC_ALL, "")std::getline()

我读到我可能需要将语言环境注入 ,但我不明白如何让它工作。std::wifstream

我对 C++ 相当陌生,所以我不确定是否有更好的工具来解决此类问题,至少我找不到任何工具。

我在 MinGW 上使用 zsh,集成到 VSCode 中。

我使用以下命令进行编译:

c++ -Wall -Wextra -Werror -std=c++20 test.cpp -o test
C++ C++20 getline wstring wifstream

评论

1赞 Remy Lebeau 9/23/2023
AFAIK,您需要使用合适的 UTF-8 编码来处理该文件。 不会削减它。imbue()wifstreamstd::localesetlocale()
0赞 Sam Varshavchik 9/23/2023
或者,忘记宽字符流。使用 、 和 。std::ifstreamstd::stringstd::cout
0赞 Remy Lebeau 9/23/2023
@SamVarshavchik 即使使用窄字符类而不是宽字符类,您仍然必须确保正确处理 UTF-8。仅仅因为文件使用 UTF-8 并不意味着控制台使用 UTF-8,等等。
0赞 Sam Varshavchik 9/23/2023
如上所述,文件的内容正确显示在终端中。
1赞 Eljay 9/23/2023
从提出的问题中我不确定。是 UTF-8 编码,还是 UTF-16 编码,还是其他编码?test.txt

答:

0赞 thepaqui 9/23/2023 #1

多亏了这篇文章,我才能够解决这个问题!
灌输是解决方案,这是解决我的问题的原因:

#include <locale>
#include <codecvt>
#include <iostream>
#include <fstream>

int main(void)
{
    setlocale(LC_ALL,"");
    std::wifstream  file("test.txt");
    file.imbue(std::locale(std::locale(), new std::codecvt_utf8<wchar_t,0x10ffff, std::consume_header>));
    std::wstring    s;
    std::getline(file, s);
    std::wcout << s << std::endl;
    return 0;
}

这一行:

file.imbue(std::locale(std::locale(), new std::codecvt_utf8<wchar_t,0x10ffff, std::consume_header>));

最初是:

file.imbue(std::locale(std::locale::empty(), new std::codecvt_utf8<wchar_t,0x10ffff, std::consume_header>));

但是,正如这个 SO 问题中所看到的那样,它是特定于平台的,所以我用它替换了它,它工作正常。std::locale::empty()std::locale()

评论

1赞 n. m. could be an AI 9/23/2023
codecvt_utf8 已弃用,仅供参考。