前因

在.net 的framewrok框架中提供的排序方法中,如string.sort() 或ArrayList.Sort()方法。这两个方法对字符串排序时,如果字符串中含有数字,则不会按数字大小排序。如:

1
2
3
4
5
6
ArrayList list = new ArrayList(4);
List.Add(“aa1”);
List.Add(“aa100);
List.Add(“aa10);
List.Add(“aa2”);
List.Sort();

我们希望排序后的顺序为:
aa1,aa2,aa10,aa100

实际上排序顺序为:
aa1,aa10,aa100,aa2

重写函数

为了序排序后的效果为我们想要的按字符串中的数值排序,我们必须重写字符串的比较函数。

由于比较两个字符串时,是逐个比较字符,先从第一个字符开始比较,取出两个字符串中的第一个字符比较,如果比较结果是大于,则说明第一个字符串大于第二个字符串,如果小于,则说明第一个字符串小于第二字符串,如果等于,则比较两个字符串中的第二个字符。如果比到最后也是相等,则说明两个字符串一样大,如果有一个字符串要多一些字符,则这个字符串在大一些。

我们改进这个算法:在比较过程中如果发现数字,则先不进行比较,看下一个字符是否为数字,这个取出两个字符串中的数字,按数字的数值大小来进行比较。如果相等再取一个字符进行比较。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
///<summary>
///主要用于文件名的比较。
///</summary>
public class FilesNameComparerClass : IComparer
{
///<summary>
///比较两个字符串,如果含用数字,则数字按数字的大小来比较。
///</summary>
///<param name="x"></param>
///<param name="y"></param>
///<returns></returns>
public int Compare(object x, object y)
{
if (x == null || y == null)
throw new ArgumentException("Parameters can't be null");
string fileA = x as string;
string fileB = y as string;
char[] arr1 = fileA.ToCharArray();
char[] arr2 = fileB.ToCharArray();
int i = 0, j = 0;
while (i < arr1.Length && j < arr2.Length)
{
if (char.IsDigit(arr1[i]) && char.IsDigit(arr2[j]))
{
string s1 = "", s2 = "";
while (i < arr1.Length && char.IsDigit(arr1[i]))
{
s1 += arr1[i];
i++;
}

while (j < arr2.Length && char.IsDigit(arr2[j]))
{
s2 += arr2[j];
j++;
}

if (int.Parse(s1) > int.Parse(s2))
{
return 1;
}

if (int.Parse(s1) < int.Parse(s2))
{
return -1;
}
}
else
{
if (arr1[i] > arr2[j])
{
return 1;
}

if (arr1[i] < arr2[j])
{
return -1;
}

i++;
j++;
}
}

if (arr1.Length == arr2.Length)
return 0;
return arr1.Length > arr2.Length ? 1 : -1;
}
}

用法

1
2
3
IComparer fileNameComparer = new FilesNameComparerClass();
List.Sort( fileNameComparer );

这样排序后的字符串就为按字符串中的数值排序了,为:

aa1,aa2,aa10,aa100