前因
在.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