Windows Explorer 文件名排序算法

Windows Explorer使用StrCmpLogicalW函数进行文件名排序,该函数对数字进行特殊处理,考虑了数字前的零。用户可以通过修改注册表来改变此行为。源代码显示,当比较两个字符串时,如果遇到数字,会处理零和数字长度,以实现更智能的排序。在数字不匹配或都是数字的情况下,会进行特定的比较。

Windows Explorer里对文件名的排序有别于普通字符串字典序排序,它调用的排序函数是 StrCmpLogicalW ,这个函数的说明请参考链接页面。那么,它是如何实现的呢?我在Windows XP SP1的系统源代码中,找到了它,现在把它贴在下面,供参考。

Explorer的这个行为,是可以通过修改注册表改变行为的:在 HKLM\Software\Microsoft\Windows\Currentversion\Policies\Explorer 中将 DWORD 变量 NoStrCmpLogical 修改为1,然后重启Explorer即可。

源代码文件路径 E:\NT\shell\shlwapi\strings.c

STDAPI_(int) StrCmpLogicalW(PCWSTR psz1, PCWSTR psz2)
{
    int iRet = 0;
    int iCmpNum = 0;
    while (iRet == 0 && (*psz1 || *psz2))
    {
        int cch1 = 0;
        int cch2 = 0;
        BOOL fIsDigit1 = IS_DIGITW(*psz1);
        BOOL fIsDigit2 = IS_DIGITW(*psz2);
        ASSERT(fIsDigit1 == TRUE || fIsDigit1 == FALSE);
        ASSERT(fIsDigit2 == TRUE || fIsDigit2 == FALSE);
        //  using bit wise XOR as logical XOR
        //  if the numbers are mismatched then n
        if (fIsDigit1 ^ fIsDigit2)
        {
            iRet = _StrCmpLocaleW(NORM_IGNORECASE, psz1, -1, psz2, -1);
        }
        else if (fIsDigit1 && fIsDigit2)
        {
            int cchZero1 = 0;
            int cchZero2 = 0;

            // eat leading zeros
            while (*psz1 == TEXT('0'))
            {
                psz1++;
                cchZero1++;
            }

            while (*psz2 == TEXT('0'))
            {
                psz2++;
                cchZero2++;
            }
            
            while (IS_DIGITW(psz1[cch1])) 
                cch1++;

            while (IS_DIGITW(psz2[cch2])) 
                cch2++;

            if (cch1 != cch2)
            {
                iRet = cch1 > cch2 ? 1 : -1;
            }
            else 
            {
                //  remember the first numerical difference
                iRet = _StrCmpLocaleW(NORM_IGNORECASE, psz1, cch1, psz2, cch2);
                if (iRet == 0 && iCmpNum == 0 && cchZero1 != cchZero2)
                {
                    iCmpNum = cchZero2 > cchZero1 ? 1 : -1;
                }
            }
        }
        else
        {
            while (psz1[cch1] && !IS_DIGITW(psz1[cch1]))
                cch1++;

            while (psz2[cch2] && !IS_DIGITW(psz2[cch2]))
                cch2++;

            iRet = _StrCmpLocaleW(NORM_IGNORECASE, psz1, cch1, psz2, cch2);

        }

        //  at this point they should be numbers or terminators or different
        psz1 = &psz1[cch1];
        psz2 = &psz2[cch2];
    }

    if (iRet == 0 && iCmpNum)
        iRet = iCmpNum;
    
    return iRet;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值