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

被折叠的 条评论
为什么被折叠?



