正如你發現的那樣,像CRT的toupper
和Win32的CharUpper
這樣的經典轉換例程是相當愚蠢的。他們一般都是在全世界被認爲是ASCII的時候歡呼起來的。
你需要的是一個語言敏感的轉換。這是一個計算上比較昂貴的操作,但也很難正確實現10很。語言很難。所以你要儘可能地將責任轉移給標準庫。由於您使用的是MFC,因此很明顯您的目標是Windows操作系統,這意味着您很幸運。您可以搭載微軟本地化工程師的辛勤工作,並提供與外殼和其他操作系統組件一致的額外好處。
您需要調用的函數是LCMapStringEx
(或者如果您仍然針對Vista之前的平臺,則爲LCMapString
)。這個函數簽名的複雜性充分證明了正確的語言意識字符串處理的複雜任務。
- 首先,您需要選擇一個區域設置。你通常希望用戶的默認語言環境,你可以用
LOCALE_NAME_USER_DEFAULT
指定,但你可以在這裏使用任何你想要的。
- 對於國旗,你會想要
LCMAP_UPPERCASE | LCMAP_LINGUISTIC_CASING
。要做相反的操作,你可以使用LCMAP_LOWERCASE | LCMAP_LINGUISTIC_CASING
。還有很多其他有趣和有用的選項需要記住。
- 然後你有一個指向源字符串的指針,它的長度是字符(代碼單元)。
- 還有一個指向字符串緩衝區的指針,該字符串緩衝區接收結果以及字符(代碼單元)的最大長度。
- 最後三個參數可以簡單地設置爲NULL或0
全部放在一起:
BOOL ConvertToUppercase(std::wstring& buffer)
{
return LCMapStringEx(LOCALE_NAME_USER_DEFAULT /* or whatever locale you want */,
LCMAP_UPPERCASE | LCMAP_LINGUISTIC_CASING,
buffer.c_str(),
buffer.length(),
&buffer[0],
buffer.length(),
NULL,
NULL,
0);
}
請注意,我在這裏做的內容就地轉化緩衝區,因此假定大寫字符串的長度與原始輸入字符串的長度完全相同。這是可能是真實的,但可能不是一個普遍安全的假設,所以你要麼想添加處理這樣的錯誤(ERROR_INSUFFICIENT_BUFFER
)和/或防守地添加一些額外的填充緩衝區。
如果您喜歡使用CRT功能,例如您現在正在使用的功能,_totupper_l
及其朋友正在圍繞LCMapString
/LCMapStringEx
進行包裝。請注意0後綴,這表示這些是區域識別轉換函數。它們允許你傳遞一個明確的語言環境,它將用於轉換。
很棒的答案。今天晚些時候我會放棄它。 –