Subversion Repositories userdetect2

Rev

Rev 69 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
69 daniel-mar 1
unit AlphaNumSort;
2
 
3
(*
4
 * The Alphanum Algorithm is an improved sorting algorithm for strings
5
 * containing numbers.  Instead of sorting numbers in ASCII order like
6
 * a standard sort, this algorithm sorts numbers in numeric order.
7
 *
8
 * The Alphanum Algorithm is discussed at http://www.DaveKoelle.com
9
 *
10
 * Translated from Java to Delphi by Daniel Marschall, www.daniel-marschall.de
11
 * Revision 2015-09-30
12
 *
13
 *
14
 * This library is free software; you can redistribute it and/or
15
 * modify it under the terms of the GNU Lesser General Public
16
 * License as published by the Free Software Foundation; either
17
 * version 2.1 of the License, or any later version.
18
 *
19
 * This library is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22
 * Lesser General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU Lesser General Public
25
 * License along with this library; if not, write to the Free Software
26
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
27
 *
28
 *)
29
 
30
interface
31
 
32
uses
33
  SysUtils;
34
 
35
function AlphaNumCompare(s1, s2: string): integer;
36
 
37
implementation
38
 
39
function isDigit(ch: char): boolean;
40
begin
41
  result := (ord(ch) >= 48) and (ord(ch) <= 57);
42
end;
43
 
44
// Length of string is passed in for improved efficiency (only need to calculate it once)
45
function getChunk(s: string; slength, marker: integer): string;
46
var
47
  chunk: string;
48
  c: char;
49
begin
50
  c := s[marker+1];
51
  chunk := chunk + c;
52
  Inc(marker);
53
  if isDigit(c) then
54
  begin
55
    while marker < slength do
56
    begin
57
      c := s[marker+1];
58
      if not isDigit(c) then break;
59
      chunk := chunk + c;
60
      Inc(marker);
61
    end;
62
  end
63
  else
64
  begin
65
    while marker < slength do
66
    begin
67
      c := s[marker+1];
68
      if (isDigit(c)) then break;
69
      chunk := chunk + c;
70
      Inc(marker);
71
    end;
72
  end;
73
  result := chunk;
74
end;
75
 
76
function AlphaNumCompare(s1, s2: string): integer;
77
var
78
  s1Length, s2Length, thisChunkLength: integer;
79
  thisMarker, thatMarker, i: integer;
80
  thisChunk, thatChunk: string;
81
begin
82
  thisMarker := 0;
83
  thatMarker := 0;
84
  s1Length := Length(s1);
85
  s2Length := Length(s2);
86
 
87
  while (thisMarker < s1Length) and (thatMarker < s2Length) do
88
  begin
89
    thisChunk := getChunk(s1, s1Length, thisMarker);
90
    Inc(thisMarker, Length(thisChunk));
91
 
92
    thatChunk := getChunk(s2, s2Length, thatMarker);
93
    Inc(thatMarker, Length(thatChunk));
94
 
95
    // If both chunks contain numeric characters, sort them numerically
96
    if isDigit(thisChunk[1]) and isDigit(thatChunk[1]) then
97
    begin
98
      // Simple chunk comparison by length.
99
      thisChunkLength := Length(thisChunk);
100
      result := thisChunkLength - Length(thatChunk);
101
      // If equal, the first different number counts
102
      if result = 0 then
103
      begin
104
        for i := 0 to thisChunkLength-1 do
105
        begin
106
          result := ord(thisChunk[i+1]) - ord(thatChunk[i+1]);
107
          if result <> 0 then Exit;
108
        end;
109
      end;
110
    end
111
    else
112
    begin
113
      result := CompareText(thisChunk, thatChunk);
114
    end;
115
 
116
    if result <> 0 then Exit;
117
  end;
118
 
119
  result := s1Length - s2Length;
120
end;
121
 
122
end.