[英]How to read non-ASCII lines from file with std::ifstream on Linux?
我試圖讀取純文本文件。 在我的情況下,我需要讀取每行的行,並處理該信息。 我知道C ++有閱讀wchars的功能。 我嘗試了以下方法:
#include <fstream>
#include <iostream>
int main() {
std::wfstream file("file"); // aaaàaaa
std::wstring str;
std::getline(file, str);
std::wcout << str << std::endl; // aaa
}
但正如你所看到的,它沒有讀完整行。 讀取“à”時會停止,這是非ASCII。 我該如何解決?
您需要了解編碼的一些基本概念。 我建議閱讀這篇文章: 絕對最低每個軟件開發人員絕對必須知道Unicode和字符集 。 基本上你不能假定每個字節是一個字母,每一個字母適合在一個char
。 此外,系統必須知道如何從文件中的字節序列中提取字母。
假設您的文件是以UTF-8編碼的,這很可能是因為您使用的是Linux。 我假設您的終端也支持它。 如果您直接使用std::string
讀取,使用chars,您將擁有一切正常工作。 看:
// olá
#include <iostream>
#include <fstream>
int main() {
std::fstream file("test.cpp");
std::string str;
std::getline(file, str);
std::cout << str << std::endl;
}
輸出是你所期望的,但這不是真的正確。 看看發生了什么:文件以utf-8編碼。 這意味着第一行是這個字節序列:
/ / o l á
47 47 32 111 108 195 161
請注意, á
用兩個字節編碼 。 如果你詢問字符串的大小( str.size()
),你的確會得到錯誤的值: 7
。 發生這種情況是因為字符串認為每個字節都是char。 當您將其發送到std::cout
,該字符串將被提供給終端進行打印。 神奇的部分:終端默認使用utf-8。 所以它只是假設字符串是utf-8並正確打印6個字符。
你看它有效,但它不是真的。 嘗試對數據進行任何字符串操作,您可能會破壞utf-8編碼,永遠無法再次打印!
我們去找wstring
。 它們使用wchar_t
存儲每個字母,在Linux上,它具有4個字節。 這足以容納任何可能的unicode字符。 但它不會直接起作用,因為默認情況下C ++使用"C"
語言環境。 區域設置是如何處理系統的各個方面的規范,例如“如何打印日期”或“如何格式化貨幣值”或甚至“如何解碼文本”。 最后一個因素很重要,默認的"C"
編碼說:“假設一切都是ASCII”。 當它正在讀取文件並嘗試解碼非ASCII字節時,它只是無聲地失敗。
更正很簡單:使用UTF-8語言環境。 看:
// olá
#include <iostream>
#include <fstream>
#include <locale>
int main() {
std::ios::sync_with_stdio(false);
std::locale loc("en_US.UTF-8"); // You can also use "" for the default system locale
std::wcout.imbue(loc); // Use it for output
std::wfstream file("test.cpp");
file.imbue(loc); // Use it for file input
std::wstring str;
std::getline(file, str); // str.size() will be 6
std::wcout << str << std::endl;
}
你可能會問std::ios::sync_with_stdio(false);
手段。 這是必需的,因為默認情況下C ++流與C流保持同步。 這很好,因為您可以在同一程序中同時使用cout
和printf
。 我們必須禁用它,因為C流將破壞utf-8編碼並將在輸出上產生垃圾。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.