Subversion Repositories userdetect2

Compare Revisions

Regard whitespace Rev 68 → Rev 69

/trunk/UserDetect2/vcl/AlphaNumSort.pas
0,0 → 1,122
unit AlphaNumSort;
 
(*
* The Alphanum Algorithm is an improved sorting algorithm for strings
* containing numbers. Instead of sorting numbers in ASCII order like
* a standard sort, this algorithm sorts numbers in numeric order.
*
* The Alphanum Algorithm is discussed at http://www.DaveKoelle.com
*
* Translated from Java to Delphi by Daniel Marschall, www.daniel-marschall.de
* Revision 2015-09-30
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*)
 
interface
 
uses
SysUtils;
 
function AlphaNumCompare(s1, s2: string): integer;
 
implementation
 
function isDigit(ch: char): boolean;
begin
result := (ord(ch) >= 48) and (ord(ch) <= 57);
end;
 
// Length of string is passed in for improved efficiency (only need to calculate it once)
function getChunk(s: string; slength, marker: integer): string;
var
chunk: string;
c: char;
begin
c := s[marker+1];
chunk := chunk + c;
Inc(marker);
if isDigit(c) then
begin
while marker < slength do
begin
c := s[marker+1];
if not isDigit(c) then break;
chunk := chunk + c;
Inc(marker);
end;
end
else
begin
while marker < slength do
begin
c := s[marker+1];
if (isDigit(c)) then break;
chunk := chunk + c;
Inc(marker);
end;
end;
result := chunk;
end;
 
function AlphaNumCompare(s1, s2: string): integer;
var
s1Length, s2Length, thisChunkLength: integer;
thisMarker, thatMarker, i: integer;
thisChunk, thatChunk: string;
begin
thisMarker := 0;
thatMarker := 0;
s1Length := Length(s1);
s2Length := Length(s2);
 
while (thisMarker < s1Length) and (thatMarker < s2Length) do
begin
thisChunk := getChunk(s1, s1Length, thisMarker);
Inc(thisMarker, Length(thisChunk));
 
thatChunk := getChunk(s2, s2Length, thatMarker);
Inc(thatMarker, Length(thatChunk));
 
// If both chunks contain numeric characters, sort them numerically
if isDigit(thisChunk[1]) and isDigit(thatChunk[1]) then
begin
// Simple chunk comparison by length.
thisChunkLength := Length(thisChunk);
result := thisChunkLength - Length(thatChunk);
// If equal, the first different number counts
if result = 0 then
begin
for i := 0 to thisChunkLength-1 do
begin
result := ord(thisChunk[i+1]) - ord(thatChunk[i+1]);
if result <> 0 then Exit;
end;
end;
end
else
begin
result := CompareText(thisChunk, thatChunk);
end;
 
if result <> 0 then Exit;
end;
 
result := s1Length - s2Length;
end;
 
end.