死xier对我做的那个“Excel图片导入程序”又有意见了,说是导入后的次序不对,99居然比101还大。我晕,自己试了下,还真的排错了。我靠,Borland的Vcl 是怎么搞的,文件的读取函数居然能读得这么糟糕。也罢,回家自己写下文件名的排序就行了。
本以为是件十分简单的事,随便弄个快速或者冒泡排序法进去就成了。没想到回家一弄,傻眼了,怎么排都错。对着排序法研究了大半夜,没错呀,是这样排的,可是排出来的怎么老是错……。偷偷的抽了根烟(可不能让xier知道),突然灵感焕发出智慧女神的光芒,问题就在于字符串大小的比较上。哈哈,哈哈哈哈,这下可有救了,差点就要被xier看扁——不过捉bug居然要靠灵感,还真越混越回去了。呵呵,不理了,先记下思路要紧(发现我的废话还真多)……
首先是字符串的分类,我自己把它分为四种:汉字、英文字母、数字、符号,这四种类型的大小次序是这样的:汉字 > 英文字母 > 数字 > 符号。对于两个字符串str1,str2,每个字符串中可以含有不同中类型字符,可以有汉字+数字+符号,可以有英文字母+数字+汉字。对于这个混合的字符串,比较的方法如下:
1、 获取str1、str2的首个字符的类型type1和type2。
2、 获取str1、str2中与首个字符相连、并类型相同的后续字符,直接该字符类型与首字符不同为止,并与首字符合成一个临时的字符串tmp1,tmp2。
3、 比较type1和type2是否不同,如果不同,通过“汉字 > 英文字母 > 数字 > 符号”比较,返回比较结果,程序结束。如果相同,进入下一歩。
4、 比较tmp1与tmp2的长度,如果长度不等,较长的为大,返回比较结果,程序序结果,如果长度相等,执行下一歩。
5、 比较tmp1与tmp2是否相等,如果不等,直接比较两个字符串大小,返回比较结果,程序结束。如果相等,执行下一步。
6、 将str1截去开头的tmp1,str2截去开头的tmp2,用剩下的字符串再从第一歩执行起(这就是传说中的递归)。
好了,看看代码(当然是Pascal了):
先看类型的定义:
type
WCharType = (Chinese,Letter,Number,Symbol); // 定义一个字符类型
Chinese是汉字,Letter是字母,Number是数字,Symbol是符号。下面是获取字符串首字符的函数:
(**
* 获取字符串首字符的类型
**)
function GetFirstType(str : string) : WCharType;
var
CType : WCharType;
begin
if str[1] in ['0'..'9'] then CType := Number
else if str[1] in ['a'..'z','A'..'Z'] then CType := Letter
else if ord(str[1]) > 128 then CType := Chinese
else CType := Symbol;
result := CType;
end;
嗯,再一个获取与首字符相同类型的后续字符,并组成字符串:
(**
* 获取与首位字符同种类型的后续字符,直到字符类型变动
**)
function GetFirstList(str : string) : string;
var
i, len : Cardinal;
firstType, otherType : WCharType;
s : string;
begin
i := 1;
firstType := GetFirstType(str);
len := Length(str);
if firstType = Chinese then //如果是汉字,i要占两位
inc(i,2)
else
inc(i,1);
while i <= len do
begin
otherType := GetFirstType(str[i]);
if otherType <> firstType then break;
if otherType = Chinese then
inc(i,2)
else
inc(i,1);
end;
s := Copy(str,1,i-1);
result := s;
end;
下面看看比较函数的主函数:
(**
* 比较两个混合字符串 。
**)
function WCharCompare(str1, str2 : string ) : integer;
var
tmp1, tmp2 : string;
flag : integer;
begin
flag := NullCompare(str1, str2); //空字符串的比较
if flag <> 2 then result := flag
else
begin
tmp1 := GetFirstList(str1);
tmp2 := GetFirstList(str2);
if GetFirstType(tmp1) = GetFirstType(tmp2) then
begin //相同类型的比较
if Length(tmp1) = Length(tmp2) then
begin //等长比较
if tmp1 > tmp2 then result := 1
else if tmp1 < tmp2 then result := -1
else //两者相等
begin
tmp1 := Copy(str1,Length(tmp1)+1,Length(str1));
tmp2 := Copy(str2,Length(tmp2)+1,Length(str2));
result := WCharCompare(tmp1,tmp2);
end;
end
else //不等长比较
if Length(tmp1) > Length(tmp2) then result := 1
else result := -1;
end
else //不同类型的比较
result := NotSameCompare(tmp1,tmp2);
end;
end;
上面是比较字符串的入口函数。另有个辅助的(怕弄在一个函数里面大长,不好看),用于首字符不同类型的字符串的比较,用在上面函数的倒数第三行 :
(**
*两个不同类型的字符串比较
**)
function NotSameCompare(str1, str2 : string) : integer;
var
type1, type2 : WCharType;
begin
type1 := GetFirstType(str1);
type2 := GetFirstType(str2);
case type1 of
Chinese : result := 1;
Letter :
begin
if type2 = Chinese then result := -1
else result := 1;
end;
Number :
begin
if type2 = Symbol then result := 1
else result := -1;
end;
Symbol : result := -1;
else
result := 0;
end;
end;
对了,还有呢,如果两个字符串中有一个是空的,或者两个都是空的呢?看下面:
(**
* 含有零的字符串的比较
**)
function NullCompare(str1, str2 : string) : integer;
begin
if (Length(str1) > 0) and (Length(str2) > 0) then result := 2
else if (Length(str1) >0) and (Length(str2) = 0) then result := 1
else if (Length (str1) = 0) and (Length(str2) > 0) then result := -1
else result := 0;
end;
呵呵,完了。呀,咋这么多,惨了惨了,这么个比较法,再加上排序,再加上把图片导入Excel的过程(xier的图片都是上千计的),那真的要当机了,看再不给主程序加线程和进度栏是不行的了。
不过是不是有更好的比较方法呢?等待着高手或者智慧女神的垂青了……