View Javadoc

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                  // no more tokens for each name, they are equal
55                  return 0;
56              }
57  
58              if (token1 == null)
59              {
60                  // the first name is shorter, it goes first
61                  return -1;
62              }
63  
64              if (token2 == null)
65              {
66                  // the second name is shorter, it goes first
67                  return 1;
68              }
69  
70              int comp = compareToken(token1, token2);
71              if (comp == 0)
72              {
73                  // the tokens are equal, move to the next tokens
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              // are we parsing a string or a number ?
99              boolean type = Character.isDigit(string.charAt(index));
100 
101             // move forward until a different character type is detected
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 }