1 /***
2 * Jetrix TetriNET Server
3 * Copyright (C) 2005 Emmanuel Bourg
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 package net.jetrix.filter;
21
22 import java.io.*;
23 import java.util.*;
24
25 /***
26 * An improved lexicographic comparator handling a number in a name as a single
27 * character. Unlike the lexicographic order where "foo1.txt" < "foo10.txt" < "foo2.txt"
28 * here we have "foo1.txt" < "foo2.txt" < "foo10.txt".
29 *
30 * todo: move this code to commons-io or commons-lang
31 *
32 * @since 0.3
33 *
34 * @author Emmanuel Bourg
35 * @version $Revision: 794 $, $Date: 2009-02-17 20:08:39 +0100 (Tue, 17 Feb 2009) $
36 */
37 public class FilenameComparator implements Comparator<File>
38 {
39 public int compare(File file1, File file2)
40 {
41 String name1 = file1.getAbsolutePath();
42 String name2 = file2.getAbsolutePath();
43
44 int index1 = 0;
45 int index2 = 0;
46
47 while (true)
48 {
49 String token1 = getToken(name1, index1);
50 String token2 = getToken(name2, index2);
51
52 if (token1 == null && token2 == null)
53 {
54
55 return 0;
56 }
57
58 if (token1 == null)
59 {
60
61 return -1;
62 }
63
64 if (token2 == null)
65 {
66
67 return 1;
68 }
69
70 int comp = compareToken(token1, token2);
71 if (comp == 0)
72 {
73
74 index1 = index1 + token1.length();
75 index2 = index2 + token2.length();
76 }
77 else
78 {
79 return comp;
80 }
81 }
82 }
83
84 /***
85 * Extract from the string the next token starting at the specified index.
86 *
87 * @param string the string to parse
88 * @param index the beginning of the token
89 */
90 String getToken(String string, int index)
91 {
92 if (string == null || string.length() == 0 || index == string.length())
93 {
94 return null;
95 }
96 else
97 {
98
99 boolean type = Character.isDigit(string.charAt(index));
100
101
102 int end = index + 1;
103 while (end < string.length() && Character.isDigit(string.charAt(end)) == type)
104 {
105 end++;
106 }
107
108 return string.substring(index, end);
109 }
110 }
111
112 /***
113 * Tells if the specified string is a number.
114 */
115 boolean isNumber(String string)
116 {
117 if (string == null || string.length() == 0)
118 {
119 return false;
120 }
121 else
122 {
123 return Character.isDigit(string.charAt(0));
124 }
125 }
126
127 /***
128 * Compare two tokens according to their types (string or number).
129 */
130 int compareToken(String token1, String token2)
131 {
132 if (isNumber(token1) && isNumber(token2))
133 {
134 return Integer.parseInt(token1) - Integer.parseInt(token2);
135 }
136 else
137 {
138 return token1.compareTo(token2);
139 }
140 }
141 }