Would the Collections folks reconsider their decision and accept such a comparator due to "popular" demand ? :) I'm attaching my implementation.
Emmanuel Bourg
Henri Yandell wrote:
I offered one of those to Collections a while back but it was turned down as it chose one specific way to do the ordering:
http://www.osjava.org/genjava/multiproject/gj-core/xref/com/generationjava/compare/NumericStringComparator.html
For your submission, I think as a comparator of Strings to Collections makes the most sense as it deals with java.util.Comparator and Lang doesn't.
Anything in my class is up for grabs if you want any of it :)
Hen
On Wed, 05 Jan 2005 01:13:13 +0100, Emmanuel Bourg <[EMAIL PROTECTED]> wrote:
Hi all, I have developped a File comparator to sort properly the files with a number in the name. For example, instead of sorting with the lexicographic order :
foo1.txt < foo10.txt < foo2.txt
it compares the numbers when the files share the same prefix and returns this order :
foo1.txt < foo2.txt < foo10.txt
This is how the "Sort by name" works in the Windows XP file explorer. Since it's quite low level I think it could be included in a commons project, but I'm not sure where:
- in [io] as a getComparator() method in FileUtils or as a FilenameComparator class ?
- in [lang] as a String comparator ?
- nowhere because this was already implemented in another well known project and I wasted my time reinventing the wheel ;)
Emmanuel Bourg
import java.io.*; import java.util.*;
/**
* An improved lexicographic comparator handling a number in a string as a
single
* character. Unlike the lexicographic order where "foo1.txt" < "foo10.txt"
< "foo2.txt"
* here we have "foo1.txt" < "foo2.txt" < "foo10.txt".
*
* @author Emmanuel Bourg
* @version $Revision$, $Date$
*/
public class NumericStringComparator implements Comparator<String>
{
public int compare(String name1, String name2)
{
int index1 = 0;
int index2 = 0;
while (true)
{
String token1 = getToken(name1, index1);
String token2 = getToken(name2, index2);
if (token1 == null && token2 == null)
{
// no more tokens for each name, they are equal
return 0;
}
if (token1 == null)
{
// the first name is shorter, it goes first
return -1;
}
if (token2 == null)
{
// the second name is shorter, it goes first
return 1;
}
int comp = compareToken(token1, token2);
if (comp == 0)
{
// the tokens are equal, move to the next tokens
index1 = index1 + token1.length();
index2 = index2 + token2.length();
}
else
{
return comp;
}
}
}
/**
* Extract from the string the next token starting at the specified index.
*
* @param string the string to parse
* @param index the beginning of the token
*/
String getToken(String string, int index)
{
if (string == null || string.length() == 0 || index == string.length())
{
return null;
}
else
{
// are we parsing a string or a number ?
boolean type = Character.isDigit(string.charAt(index));
// move forward until a different character type is detected
int end = index + 1;
while (end < string.length() &&
Character.isDigit(string.charAt(end)) == type)
{
end++;
}
return string.substring(index, end);
}
}
/**
* Tells if the specified string is a number.
*/
boolean isNumber(String string)
{
if (string == null || string.length() == 0)
{
return false;
}
else
{
return Character.isDigit(string.charAt(0));
}
}
/**
* Compare two tokens according to their types (string or number).
*/
int compareToken(String token1, String token2)
{
if (isNumber(token1) && isNumber(token2))
{
return Integer.parseInt(token1) - Integer.parseInt(token2);
}
else
{
return token1.compareTo(token2);
}
}
}
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
