|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionDid you notice how Explorer in XP is intelligent enough to sort the files in a natural order? If you have 10 files on your hard disk, they will show in this order: file1.txt
file2.txt
file3.txt
file4.txt
file5.txt
file6.txt
file7.txt
file8.txt
file9.txt
file10.txt
However, if you try in under DOS, they will appear this way: file1.txt
file10.txt
file2.txt
...
The reason for that is that DOS uses a simple alphabetical search. The aim of this article is to show how I think Explorer does this better than DOS and provide to the CodeProject readers a class to reproduce this in their .NET programs. BackgroundThe .NET framework uses the 'VB
Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer
//C#
int IComparer.Compare(object x, object y)
The function you must provide returns an integer which must be:
Comparing a Using the codeThe class In the demo program, for example, I use: Array.Sort(lines, New NaturalComparer())
This will sort the lines using the natural order I have briefly described above. How does this workThis The public void NextToken()
{
do
{
if (mCurChar == '\0')
{
mTokenType = NaturalComparer.TokenType.Nothing;
mStringValue = null;
return;
}
else if (char.IsDigit(mCurChar))
{
mTokenType = NaturalComparer.TokenType.Numerical;
ParseNumericalValue();
return;
}
else if (char.IsLetter(mCurChar))
{
mTokenType = NaturalComparer.TokenType.String;
// This can also optionally return
// numericals in case of Roman Numerals
ParseString();
return;
}
else
{
// Ignore this character and loop some more
NextChar();
}
} while (true);
}
The The int System.Collections.Generic.IComparer<string>.Compare(string string1,
string string2)
{
mParser1.Init(string1);
mParser2.Init(string2);
int result;
do
{
if (mParser1.TokenType == TokenType.Numerical &
mParser2.TokenType == TokenType.Numerical)
// both string1 and string2 are numerical
result = decimal.Compare(mParser1.NumericalValue, mParser2.NumericalValue);
else
result = string.Compare(mParser1.StringValue, mParser2.StringValue);
if (result != 0) return result;
else
{
mParser1.NextToken();
mParser2.NextToken();
}
} while (!(mParser1.TokenType == TokenType.Nothing &
mParser2.TokenType == TokenType.Nothing));
return 0; //identical
}
Points of interestAs an option, you can ask the New NaturalComparer(NaturalComparerOptions.RomanNumbers)
The problem is that sometimes the comparer could mix a valid English name for a Roman number. This is okay if the other side of the comparison is a string, but it can mess your sort order if the other side is a number or another false Roman numeral positive. So, use this option if you believe the likelihood of having Roman numerals is worth messing the order. History
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||