2012年10月24日 星期三

字串比較規則

在應用程式中,若可條列出來的資料量不少,通常會幫用戶做排序的動作,
如果是以字串比對排序大小的方式常常會使用 CString.Compare()
但 CString.Compare() 比對大小時,規則是以 Unicode 來比較兩個字串的大小,
在這種情況下,很有可能會發生一種不直覺的現像如下

CString sA = _T("張"); // Unicode 為 5F35
CString sB = _T("王"); // Unicode 為 738B
CString sC = _T("陳"); // Unicode 為 9673
int nAB = sA.Compare(sB); // nAB 為 -1,張比王小
int nBC = sB.Compare(sC); // nBC 為 -1,王半陳小
// 比較後的結果為 張 < 王 < 陳,排起來沒有視覺上的順序可參考

另一種比較字串的方式可以使用 lstrcmp 比較兩個 CString
lstrcmp 的規則不是使用 Unicode 碼來做比較,
lstrcmp 的規則是依使用者的語系相關設定來做比較,
設定方式在:控制台、語言和區域、變更日期時間或數字格式、更變排序方式,
當然,用戶選擇了筆劃、注音、部首後排起來的結果會大不相同,
如果想要知道用戶選的是什麼排序規則,可以利用以下方式

LCID lcidSystem  = GetSystemDefaultLCID(); // 系統預設 Locale ID
LCID lcidUser = GetUserDefaultLCID(); // 使用者設定的 Locale ID
WORD PrimID = PRIMARYLANGID(lcidUser); // 用戶的主要語系
WORD SystemSubID = SUBLANGID(lcidUser); // 用戶的次要語系
if(SystemPrimID == LANG_CHINESE && SystemSubID == SUBLANG_CHINESE_TRADITIONAL)
{
    // 代表用戶的 OS 是中文且繁體版
}
UINT uUserSortID = SORTIDFROMLCID(lcidUser); // 用戶的排序規則
if(uUserSortID == SORT_CHINESE_BOPOMOFO)
{
    // 用戶選擇了 Bopomofo 排序
}

在使用 lstrcmp 比較兩個字串,如果作業系統中選擇的排序規則不符合我們的需求,
其實是可以改用 CompareStringW 來比較字串,因為它可以自訂比較規則,方法如下

CString strA = _T("靠"); // 15 劃
CString strB = _T("岸"); // 8 劃
LCID lcid = ::GetThreadLocale(); // 先取得用戶的 LCID
if(lcid == 0x00000404)
{
    // 用戶在系統語系設定中選擇了預設的筆劃比較,但我們想要以注音比較字串大小
    LCID wordBopomofoLCID = 0x00030404; // 注音排序的 LCID
    int nCustomCompare = ::CompareStringW(wordBopomofoLCID, NORM_IGNORECASE, strA, strA.GetLength(), strB, strB.GetLength());
    // 因為 ㄎ 比 ㄢ 小,故 nCustomCompare 結果為 CSTR_LESS_THAN
}

如此即可對不同語言、不同環境下使用不同的比較規則來排序資料。

沒有留言:

張貼留言