I'm not sure if this is suitable for inclusion in collections - but I've
found it to be fairly useful when comparing StringS.
The problem solved:
Does 11 come before or after 2,3,4,5...?
Other features:
Ascending/descending comparison
Blanks are high/low.
I've included the test case class.
Salu2.
Jim
package org.apache.commons.collections;
import java.io.Serializable;
import java.util.Comparator;
/**
* Provides comparison of two Strings that may be numbers, such that the
* comparison between two numbers is coherent: the numbers 10,1,2,21,11 are
* ordered as 1,2,10,11,21. Blanks are optional placed at the top of an
* ascending pile (default behaviour) or at the bottom after a call to
* setBlankPosition(false). The sort is ascending by default: this can be set
* to descending by calling setDirection(false).
*
*@author Jim Cheesman
*@created August 30, 2001
*/
public class NumericStringComparator implements Comparator, Serializable {
int direction = 1;
int blankPosition = 1;
/**
* Constructor for NumericStringComparator
*/
public NumericStringComparator() {
super();
}
/**
* Constructor for NumericStringComparator
*
*@param ascending true for ascending sort
*@param blankHigh true to consider blanks as higher than any other String
*/
public NumericStringComparator(boolean ascending, boolean blankHigh) {
super();
setDirection(ascending);
setBlankPosition(blankHigh);
}
/**
* Are blanks treated as high (i.e. after all other values - default) or low
* (before all other values.)
*
*@param blankHigh true implies blanks appear at the end of a sorted set
*/
public void setBlankPosition(boolean blankHigh) {
if (blankHigh) {
blankPosition = 1;
}
else {
blankPosition = -1;
}
}
/**
* Sets the direction of the sort: ascending or descending. Ascending implies
* low ->high; descending high ->low.
*
*@param ascending true if ascending
*/
public void setDirection(boolean ascending) {
if (ascending) {
direction = 1;
}
else {
direction = -1;
}
}
/**
* Compares two Strings.
*
*@param o1 The first String, as an Object
*@param o2 The second String, as an Object
*@return -1 if o1 <o2, 0 or 1.
*/
public int compare(Object o1, Object o2) {
String s1 = (String) o1;
String s2 = (String) o2;
boolean b1 = (o1 == null || isBlank(s1));
boolean b2 = (o2 == null || isBlank(s2));
if (b1 || b2) {
return (direction * compareBlanks(b1, b2));
}
if (isNumber(s1) && isNumber(s2)) {
return (direction * (Integer.valueOf(s1).compareTo(Integer.valueOf(s2))));
}
else {
return (direction * s1.compareTo(s2));
}
}
/**
* Checks for equality with another comparator.
*
*@param o The Comparator to check against.
*@return true if o is a NumericStringComparator
*/
public boolean equals(Object o) {
return (o instanceof NumericStringComparator);
}
/**
* Checks if a String is a blank - only spaces, carriage returns etc. Defined
* as toCheck.trim().length() == 0.
*
*@param toCheck The String to check
*@return The Blank
*@returns true if blank
*/
boolean isBlank(String toCheck) {
return (toCheck.trim().length() == 0);
}
/**
* Gets the Number
*
*@param toCheck Description of Parameter
*@return The Number
*/
boolean isNumber(String toCheck) {
char[] check = toCheck.trim().toCharArray();
for (int i = 0; i < check.length; i++) {
if (check[i] < '0' || check[i] > '9') {
return false;
}
}
return true;
}
/**
* Compares blanks: blanks should come last in the set, which implies they
* have the highest value.
*
*@param b1 true if the first is blank
*@param b2 true if the second is blank
*@return Description of the Returned Value
*@returns If both are blank, returns 0; if the first is blank, 1; -1
* otherwise.
*/
int compareBlanks(boolean b1, boolean b2) {
if (b1 && b2) {
return 0;
}
if (b1) {
// yeah, the "1" is a little superfluous... but it makes it clearer
return (blankPosition * 1);
}
return (blankPosition * -1);
}
}
package org.apache.commons.collections;
import java.util.*;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/**
* Test class for the AlphaNumericComparator
*
*@author Jim Cheesman
*@created August 30, 2001
*/
public class TestNumericStringComparator extends TestCase {
private TreeSet set;
private NumericStringComparator nsc = new NumericStringComparator();
/**
* Constructor for TestNumericStringComparator
*
*@param name Description of Parameter
*/
public TestNumericStringComparator(String name) {
super(name);
}
/**
* Assembles and returns a test suite for all the test methods of this test
* case.
*
*@return A non-null test suite.
*/
public static Test suite() {
TestSuite suite = new TestSuite(TestNumericStringComparator.class);
return suite;
}
/**
* Run the test case.
*
*@param args Description of Parameter
*/
public static void main(String args[]) {
String[] testCaseName = {TestNumericStringComparator.class.getName()};
junit.textui.TestRunner.main(testCaseName);
}
/**
* A unit test for JUnit
*/
public void testWithNoNumbers() {
loadSet(new String[]{"E", "F", "A", "C", "B", "D"});
boolean check = checkAgainst(new String[]{"A", "B", "C", "D", "E", "F"});
assertTrue("Sort not correct?", check);
}
/**
* A unit test for JUnit
*/
public void testWithAllNumbers() {
loadSet(new String[]{"3", "5", "21", "1", "11", "2", "4"});
boolean check = checkAgainst(new String[]{"1", "2", "3", "4", "5", "11", "21"});
assertTrue("Sort not correct?", check);
}
/**
* A unit test for JUnit
*/
public void testWithMixNumbersAndStrings() {
loadSet(new String[]{"B", "1", "11", "c", "A", "C", "21", "2", " "});
boolean check = checkAgainst(new String[]{"1", "2", "11", "21", "A", "B", "C",
"c", " "});
assertTrue("Sort not correct?", check);
}
/**
* A unit test for JUnit
*/
public void testWithMixNumbersAndStringsDescending() {
nsc.setDirection(false);
loadSet(new String[]{"B", "1", "11", "A", "C", "21", "2", " "});
boolean check = checkAgainst(new String[]{" ", "C", "B", "A", "21", "11", "2",
"1"});
assertTrue("Sort not correct?", check);
}
/**
* A unit test for JUnit
*/
public void testWithMixNumbersAndStringsDescendingBlankLow() {
nsc.setDirection(false);
nsc.setBlankPosition(false);
loadSet(new String[]{"B", "1", "11", "A", "C", "21", "2", " "});
boolean check = checkAgainst(new String[]{"C", "B", "A", "21", "11", "2", "1", "
"});
assertTrue("Sort not correct?", check);
}
/**
* A unit test for JUnit
*/
public void testWithMixNumbersAndStringsBlankLow() {
nsc.setBlankPosition(false);
loadSet(new String[]{"B", "1", "11", "A", "C", "21", "c", "2", " "});
boolean check = checkAgainst(new String[]{" ", "1", "2", "11", "21", "A", "B",
"C", "c"});
assertTrue("Sort not correct?", check);
}
/**
* A unit test for JUnit
*/
public void testIsNumber() {
boolean check = nsc.isNumber("A");
assertTrue("A is a number???", !check);
check = nsc.isNumber("12");
assertTrue("12 is not a number???", check);
}
/**
* Sets up the text fixture. Called before every test case method.
*/
protected void setUp() {
set = new TreeSet(nsc);
}
/**
* Tears down the text fixture. Called after every test case method.
*/
protected void tearDown() {
set = null;
}
/**
* Utility method to load the set.
*
*@param values Description of Parameter
*/
private void loadSet(String[] values) {
for (int i = 0; i < values.length; i++) {
set.add(values[i]);
}
}
/**
* Utility method to check the contents of set against the array passed as an
* argument
*
*@param values Description of Parameter
*@return Description of the Returned Value
*/
private boolean checkAgainst(String[] values) {
Iterator iterator = set.iterator();
int i = 0;
if (values.length != set.size()) {
return false;
}
while (iterator.hasNext()) {
String toCheck = (String) iterator.next();
if (!toCheck.equals(values[i])) {
return false;
}
i++;
}
return true;
}
}
--
* Jim Cheesman *
Trabajo:
[EMAIL PROTECTED] - (34)(91) 724 9200 x 2360
Exaggeration is not
all it's cracked up to be.