字符破折號在UTF-16(在小端0x14 0x20
),0xE2 0x80 0x94
在UTF-8,並在所有取決於所使用的字符集代碼和頁面上的其他碼或不代碼編碼爲U+2014
。 Windows-1252代碼頁(在西歐語言中很常見)具有破折號字符0x97
,我們可以認爲它是等效的。
Windows在內部管理UTF-16路徑,因此每次使用其錯誤的ANSI接口(功能以A
結尾)調用該函數時,路徑將使用爲用戶配置的當前代碼頁轉換爲UTF-16。
另一方面,C和C++的RTL可以實現訪問「ANSI」或「Unicode」(以W
結尾的函數)接口。在第一種情況下,用於表示字符串的代碼頁必須與用於系統的代碼頁相同。在第二種情況下,我們可以從頭開始直接使用utf-16字符串,或者用於轉換爲utf-16的函數必須配置爲使用源字符串的相同代碼頁進行映射。
是的,這是一個複雜的問題。有幾個錯誤(或問題)的建議來解決這個問題:
- 使用
wfstream
代替fstream
:wfstream
做什麼可以與之fstream
不同的路徑。沒有。它只是意味着「管理像wchar_t
的字節流」。 (它以一種不同的方式做到了這一點,因此在大多數情況下使這個階級變得毫無用處,但這是另一個歷史)。要在Visual Studio實現中使用Unicode接口,它存在重載的構造函數和接受const wchar_t*
的函數open()
。這些函數和構造函數都被重載爲fstream
和wfstream
。使用fstream
與正確的open()
。
mbstowcs()
:這裏的問題是語言環境(其中包含字符串中使用的代碼頁)使用。如果由於缺省語言環境匹配系統語言環境而匹配語言環境,那麼酷。如果沒有,你可以試試mbstowcs_l()
。但是這些函數是不安全的C函數,所以你必須小心緩衝區大小。無論如何,只有在運行時才能獲得轉換路徑,這種方法纔有意義。如果它是編譯時已知的靜態字符串,最好直接在代碼中使用它。
L"C:\\temp\\test—1.dgn"
:字符串中的L
前綴並不意味着「將此字符串轉換爲utf-16」(源代碼使用8位字符),至少在Visual Studio實現中不存在。 L
前綴的意思是「在引號之間的每個字符之後添加一個0x00
字節」。因此,—
相當於在窄(普通)字符串中的字節0x97
,它在寬(前綴爲L
)字符串但不是0x14 0x20
時變爲0x97 0x00
。相反,它是更好地使用它的通用字符名稱:L"C:\\temp\\test\\u20141.dgn"
一種流行的做法是在代碼中使用UTF-8或UTF-16一直使用,只有在絕對必要時進行轉換。將具有特定代碼頁的字符串轉換爲utf-8或utf-16時,首先嚐試將其轉換爲其中一個(utf-8或utf-16),以標識第一個正確的代碼頁。要做這種轉換,根據它們來自哪裏來使用這些功能。如果你從XML文件中得到你的字符串,那麼通常在那裏解釋使用的代碼頁(並用作utf-8)。如果它來自Windows控件,請使用Windows API函數,如MultiByteToWideChar
。 (CP_ACP
或GetACP()
用作默認代碼頁)。
始終使用fstream
(而不是wfstream
)及其寬接口(open
和構造函數),而不是其狹窄的接口。 (您可以再次使用MultiByteToWideChar
將utf-8轉換爲utf-16)。
對於這種方法,有幾篇文章和建議。其中之一,我建議你:http://www.nubaria.com/en/blog/?p=289。
首先,您需要說明您的文件名實際包含哪些字節。將一個emdash(0x2014)傳遞給fopen將在技術上與某些轉換或將其分割爲兩個字節或其他內容,但之後它不會成爲emdash。使用例如。 FindFirstFileW/FindNextFileW等,然後查看原始字節值。 – deviantfan
對不起,應該澄清一點,我只是有一個普通的舊式C風格的單字節字符串,而不是UTF8。 em-dash表示爲單個字節 - 0x97,它應該是標準的ANSI 8位字符。 – Piers