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. |