# added a natural order comparator (i.e. "R9" < "R10")

This commit is contained in:
Lukas Niemeier committed 2013-05-13 18:27:02 +02:00
1 parent b551592cfa
commit ad6e4de5a1
2 files changed
+176

No files matched your search

@@ -2,6 +2,7 @@ package com.sap.sailing.domain.common.impl;
import java.io.Serializable;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
@@ -230,5 +231,80 @@ public class Util {
return "[" + a + ", " + b + ", " + c + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
}
/**
* Natural Order String Comparison inspired by the idea of Martin Pool and Dave Koelle.
*
* Natural order compares mixed (alphanumeric) string in a more intuitive way:
* a < a0 < a1 < a1a < a1b < a2 < a10 < a20
*
*/
public static class NaturalComparator implements Comparator<String> {
/**
* Compare the passed strings in natural order.
*/
@Override
public int compare(String a, String b) {
int result = 0;
int aIndex = 0;
int bIndex = 0;
int aLength = a.length();
int bLength = b.length();
while(aIndex < aLength && bIndex < bLength) {
// Get next block of all-char or all-digit substring
String aBlock = getBlock(a, aIndex);
aIndex += aBlock.length();
String bBlock = getBlock(b, bIndex);
bIndex += bBlock.length();
// Compare all-digit blocks as numbers - all-char blocks as strings
if (Character.isDigit(aBlock.charAt(0)) && Character.isDigit(bBlock.charAt(0))) {
result = Integer.valueOf(aBlock).compareTo(Integer.valueOf(bBlock));
} else {
result = aBlock.compareTo(bBlock);
}
if (result != 0) {
return result;
}
}
// Strings may be of different size
return aLength - bLength;
}
private String getBlock(String value, int index) {
int valueLength = value.length();
StringBuilder blockBuilder = new StringBuilder();
char ch = value.charAt(index++);
blockBuilder.append(ch);
if (Character.isDigit(ch)) {
while (index < valueLength) {
ch = value.charAt(index++);
if (!Character.isDigit(ch)) {
break;
} else {
blockBuilder.append(ch);
}
}
} else {
while (index < valueLength) {
ch = value.charAt(index++);
if (Character.isDigit(ch)) {
break;
} else {
blockBuilder.append(ch);
}
}
}
return blockBuilder.toString();
}
}
}
@@ -0,0 +1,100 @@
package com.sap.sailing.domain.common.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Before;
import org.junit.Test;
import com.sap.sailing.domain.common.impl.Util.NaturalComparator;
public class NaturalComparatorTest {
private NaturalComparator comparator;
@Before
public void setUp() {
comparator = new NaturalComparator();
}
@Test
public void testEmpty() {
assertTrue(comparator.compare("", "a") < 0);
assertTrue(comparator.compare("a", "") > 0);
assertEquals(0, comparator.compare("", ""));
}
@Test
public void testSimpleCharOrder() {
assertTrue(comparator.compare("a", "b") < 0);
assertTrue(comparator.compare("aa", "ab") < 0);
assertTrue(comparator.compare("aaa", "aab") < 0);
assertTrue(comparator.compare("aaa", "aaab") < 0);
assertEquals(0, comparator.compare("abc", "abc"));
}
@Test
public void testSimpleNumberOrder() {
assertTrue(comparator.compare("0", "1") < 0);
assertTrue(comparator.compare("00", "1") < 0);
assertTrue(comparator.compare("2", "6") < 0);
assertTrue(comparator.compare("9", "10") < 0);
assertTrue(comparator.compare("9", "100") < 0);
assertTrue(comparator.compare("198", "200") < 0);
assertEquals(0, comparator.compare("0", "0"));
}
@Test
public void testCaseOrder() {
assertTrue(comparator.compare("A", "a") < 0);
assertTrue(comparator.compare("Z", "a") < 0);
assertEquals(0, comparator.compare("AbCd123", "AbCd123"));
}
@Test
public void testLeadingOrder() {
assertTrue(comparator.compare("0001", "002") < 0);
assertTrue(comparator.compare(" 0 0 1", "2") < 0);
assertTrue(comparator.compare("002b", "2c") < 0);
assertTrue(comparator.compare("001a", "0001a") < 0);
assertTrue(comparator.compare("0001a", "001b") < 0);
assertEquals(0, comparator.compare("01", "01"));
}
@Test
public void testDigitVsCharOrder() {
assertTrue(comparator.compare("0", "a") < 0);
assertTrue(comparator.compare("0", "A") < 0);
assertTrue(comparator.compare("9", "a") < 0);
assertTrue(comparator.compare("9", "A") < 0);
}
@Test
public void testMixedOrder() {
assertTrue(comparator.compare("a42", "a300") < 0);
assertTrue(comparator.compare("a1b2c3d4e5", "a1b2c9d4e5") < 0);
assertTrue(comparator.compare("a1b2c3d4e5", "a1b2z3d4e5") < 0);
assertTrue(comparator.compare("a1b2 c3d4e5", "a1b2c3d4e5") < 0);
assertTrue(comparator.compare("a9b11", "a10b11") < 0);
assertTrue(comparator.compare("a9b9", "a9b10") < 0);
assertTrue(comparator.compare("a12", "a123") < 0);
assertTrue(comparator.compare("123", "1234") < 0);
assertTrue(comparator.compare("12abc", "12abcd5") < 0);
assertTrue(comparator.compare("R1", "R10") < 0);
assertTrue(comparator.compare("R 1", "R 10") < 0);
assertTrue(comparator.compare("G1", "G10") < 0);
assertTrue(comparator.compare("G 1", "G 10") < 0);
}
@Test
public void testDotsOrder() {
assertTrue(comparator.compare("0.1", "0.2") < 0);
assertTrue(comparator.compare("0.01", "0.2") < 0);
assertTrue(comparator.compare("0.1.5b", "0.2a") < 0);
}
}