2016-12-03 89 views
2

我有這樣的代碼字母轉換爲大寫:將字符轉換爲大寫阿拉伯文

// make this character upper 
if(_istalpha(zChar) && !_istupper(zChar)) 
    pMsg->wParam = (WPARAM)_toupper(zChar); 

它已經工作多年了。最近我被要求支持阿拉伯語,我的用戶說信件被損壞了。這是因爲上面的代碼。

我被告知阿拉伯語,大寫字母不適用。我知道我可以測試我的程序設置,看看他們是否使用阿拉伯語並避免使用此代碼。但還有另一種方式嗎?

我知道你的日期,你首先打電話給_tsetlocale

更新:

位於此話題有關toupper其中提到區域設置!將嘗試它。

回答

2

正如你發現的那樣,像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​​後綴,這表示這些是區域識別轉換函數。它們允許你傳遞一個明確的語言環境,它將用於轉換。

+0

很棒的答案。今天晚些時候我會放棄它。 –

0

我假設你使用的是UTF-8字符串。在這種情況下,您的代碼需要能夠識別UTF-8,即能夠說明多字節字符。例如,如果雙字節字符串中的第二個字符恰好與字母'c'相同,則它將被您的代碼拾取並轉換爲大寫,從而產生完全不同的雙字節字符。 看看這個問題: Convert a unicode String In C++ To Upper Case