I need a good alphanumerical sorting routine written in delphi.
Normally, WideCompareStr will arrange strings like this:
text1
text12
text123
text2
text3
Instead of that, I need to arrange my strings this way:
text1
text2
text3
text12
text123
I've been searching the net hours for a routine like this, but didn't find
any.
Any help would be greatly appreciated!
Note: It should just be a basic comparision routine that I can use to
arrange TListView columns!
Thanks!
Veronica
I'm not surprised that you can't find anything. You have a compound key the first part is text and the second part is a number. The easiest way to handle it is to left pad the numbers either with a space or 0 which makes sorting easy ..
text001
text002
text003
text012
text123
otherwise you have to split the string into its component string and number, do a first sort on the text and then sort within that for the number and I have no idea how to do that.
Roy Lambert
Most list components have the ability to call a method
when they compare two items for sorting. You can use that
method to compare the two parts of each string.
First you need a function to strip off the numeric part
and return the string:
(This is assuming that there will be no numbers within
the actual string portion of the data.)
function StripNumbers(Value: string): string;
var
x: integer;
begin
x := 1;
while (x < length(Value) and not (Value[x] in ['0'..'9']) do
inc(x);
result := copy(Value, 1, x - 1);
end;
Then you need a function for stripping off the number:
(The function below ignores leading characters until
it reaches any numeric(integer) sign, including minus, plus and
commas. I have another which does the same for floating
point numbers. I use both regularly for things like this.)
function GetNumber(Value: string): integer;
var
x: integer;
s1: string;
Neg: boolean;
begin
Value := Trim(Value);
if Value = '' then
Result := 0
else
try
Neg := False;
s1 := '0';
for x := 1 to length(s) do
if Value[x] in ['-', '+', '0'..'9', ','] then begin
if not (Value[x] in ['-', ',']) then
s1 := s1 + Value[x]
else if (Value[x] = '-') and (x = 1) then
Neg := True;
end else if s1 <> '0' then
break;
Result := StrToInt(s1);
if Neg then
Result := Result * -1;
except
Result := 0;
end;
end;
Now, you can just compare the two parts in your sorting
routine. If the string portions are equal, then test the
numeric portion.
HTH
Woody (TMW)
brings back quite a few hits. The first a link to some code and the second
a pretty good discussion with links to some paper on natural sort.
--
Iman
StrCmpLogicalW() does what you want.
....
function StrCmpLogicalW(psz1, psz2: PWideChar): Integer; Stdcall;
procedure SortLogicalW(Strs: TStrings);
implementation
function StrCmpLogicalW; external 'shlwapi.dll' name 'StrCmpLogicalW';
procedure SortLogicalW(Strs: TStrings);
function _SortW(List: TStrings; Index1, Index2: Integer): Integer;
begin
result := StrCmpLogicalW( PWideChar(WideString(List[Index1])),
PWideChar(WideString(List[Index2])) );
end;
var
buffer : TStringList;
begin
if Strs.Count > 1 then begin
buffer := TStringList.Create;
try
buffer.Assign(Strs);
buffer.CustomSort(@_SortW);
Strs.Assign(buffer);
finally
buffer.Free;
end;
end;
end;