I have an Arabic file (ASCII), which contains: 121101 الزبون كمال 121102 الزبون سعيد 121103 الزبون عمار
一些澄清後,OP想:
to write general function which read uft8 and ANSI files
爲了能夠治療以同樣的方式的內容,我建議轉換爲UTF-16編碼std::wstring
。 OP似乎是針對Windows平臺開發的,其中UTF-16是大多數API所期望的編碼。在其他平臺(Linux)上,可能更適合將所有內容轉換爲UTF-8。
閱讀ANSI文本文件轉換成UTF-16編碼的wstring
爲了能夠ANSI(又稱擴展ASCII)解碼,我們必須知道文件的codepage。
可以通過流的imbue()
方法來定義代碼頁(或更準確地說,區域設置)。在你的情況下,代碼頁是1256。
下面的示例讀取被編碼與ANSI代碼頁1256和顯示使用MessageBoxW()
其預計的UTF-16編碼的字符串的文本的文本文件的內容:
#include <fstream>
#include <string>
#include <codecvt>
#include <Windows.h>
int main()
{
// Use wifstream because we want to read content into a wstring.
std::wifstream f{"test.txt"};
// Define the code page of the text file (1256 = Arabic)
f.imbue(std::locale(".1256"));
// Read the whole file into a wstring.
// The stream converts from ANSI to UTF-16 encoding.
std::wstring s{ std::istreambuf_iterator<wchar_t>(f), std::istreambuf_iterator<wchar_t>() };
// Display the string which is now UTF-16 encoded.
::MessageBoxW(NULL, s.c_str(), L"test", 0);
return 0;
}
注:本std::locale
參數是平臺特定的。 「.1256」適用於Windows平臺,但這可能不適用於Linux。
閱讀UTF-8編碼的文本文件轉換成UTF-16編碼的wstring
爲此,我們可以採用std::codecvt_utf8_utf16
方面。 用下面的代碼替換imbue()
呼叫前面的例子中:
f.imbue(std::locale(f.getloc(),
new std::codecvt_utf8_utf16< wchar_t, 1114111UL, std::consume_header>));
std::consume_header
跳過byte order mark如果它存在的標誌。
注:
- 代碼樣本已與VS2017的Windows 10下進行了測試與德國的本地化。
- 爲簡潔起見,我省略了錯誤處理。流狀態應在打開後和流之後檢查。
創建一個通用的解決方案
以上的代碼示例需要你知道的文本文件的編碼事前。以真正通用的方式檢測文本文件的編碼是一項艱鉅的任務,因爲沒有這樣做的標準方法。它不能可靠地完成,你必須使用一些啓發式。
如果你可以對你必須處理的文件做一些假設,你可以編寫一個簡單的檢測函數。說這些文件只分爲以下幾類:
然後,你可以閱讀前3個字節使用std::ifstream
的文件,並將它們與{0xEF, 0xBB, 0xBF}
進行比較。如果相等,則可以相對確定該文件是UTF-8編碼的,因爲非UTF-8編碼文件不太可能以這些字節開始。如果不相等,則會假設代碼頁1256.
ASCII沒有阿拉伯字符。找出它實際上是什麼編碼並讀取它,但'iostream'不是那麼好,所以你可能想使用一個OS特定的函數或其他庫來爲你做。 – nwp
據我所知ASCII有一個代碼頁參數,我怎麼能通過這個參數ifstream! –
你可以用'wifstream :: imbue()'方法做到這一點,看我的答案。 – zett42