# HG changeset patch # User igerasim # Date 1418637891 -10800 # Node ID 6c4fbcfc615d8f2d160579007635481d805da8a4 # Parent 678faa7d1a6af199864a4f7f9208cbbdf19ee4e2 AlphaNumeric: sample diff --git a/src/sample/share/comparator/AlphaNumericCharArrayComparator.java b/src/sample/share/comparator/AlphaNumericCharArrayComparator.java new file mode 100644 --- /dev/null +++ b/src/sample/share/comparator/AlphaNumericCharArrayComparator.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + +package comparator; + +import java.util.Comparator; + +class AlphaNumericCharArrayComparator implements Comparator +{ + final Comparator charComparator; + + public AlphaNumericCharArrayComparator() { + this(Character::compare); + } + + public AlphaNumericCharArrayComparator(Comparator charComparator) { + this.charComparator = charComparator; + } + + /** + * Counts how many consequtive characters in the array {@code o} + * are digits, starting from the position {@code from}. + */ + private int countDigits(char[] o, int from) { + for (int i = from; ; ++i) { + if (i == o.length || !Character.isDigit(o[i])) { + return (i - from); + } + } + } + + @Override + public int compare(char[] o1, char[] o2) { + final int minLength = Integer.min(o1.length, o2.length); + int numStart1 = 0; + int index = 0; + + // skip common prefix of the arguments + while (index < minLength && + charComparator.compare(o1[index], o2[index]) == 0) + { + if (!Character.isDigit(o1[index++])) { + numStart1 = index; + } + } + + int numCount1 = index - numStart1; + if (numCount1 > 0 || + (index < minLength && + Character.isDigit(o1[index]) && + Character.isDigit(o2[index]))) + { + // first different char is digit + int numCount2 = numCount1; + int numStart2 = numStart1; + + numCount1 += countDigits(o1, index); + numCount2 += countDigits(o2, index); + + int numCountWithZeros1 = numCount1; + int numCountWithZeros2 = numCount2; + + while (numCount1 < numCount2) { + if (charComparator.compare(o2[numStart2], '0') != 0) { + return -1; + } + numStart2++; + numCount2--; + } + + while (numCount2 < numCount1) { + if (charComparator.compare(o1[numStart1], '0') != 0) { + return 1; + } + numStart1++; + numCount1--; + } + + // here numCount1 == numCount2; + while (numCount1-- > 0) { + int res = charComparator.compare(o1[numStart1++], o2[numStart2++]); + if (res != 0) { + return res; + } + } + + if (numCountWithZeros1 != numCountWithZeros2) { + return (numCountWithZeros1 < numCountWithZeros2) ? -1 : 1; + } + + } + + // otherwise, compare literally + for (;; ++index) { + if (index < o1.length) { + if (index < o2.length) { + int res = charComparator.compare(o1[index], o2[index]); + if (res != 0) { + return res; + } + } else { + return 1; + } + } else { + if (index < o2.length) { + return -1; + } + return 0; + } + } + } +} diff --git a/src/sample/share/comparator/AlphaNumericStringComparator.java b/src/sample/share/comparator/AlphaNumericStringComparator.java new file mode 100644 --- /dev/null +++ b/src/sample/share/comparator/AlphaNumericStringComparator.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + +package comparator; + +import java.util.Comparator; + +class AlphaNumericStringComparator implements Comparator +{ + final Comparator charComparator; + + public AlphaNumericStringComparator() { + this(Character::compare); + } + + public AlphaNumericStringComparator(Comparator charComparator) { + this.charComparator = charComparator; + } + + /** + * Counts how many consequtive characters in the string {@code o} + * are digits, starting from the position {@code from}. + */ + private int countDigits(String o, int from) { + final int oLength = o.length(); + for (int i = from; ; ++i) { + if (i == oLength || !Character.isDigit(o.charAt(i))) { + return (i - from); + } + } + } + + @Override + public int compare(String o1, String o2) { + final int minLength = Integer.min(o1.length(), o2.length()); + int numStart1 = 0; + int index = 0; + + // skip common prefix of the arguments + while (index < minLength && + charComparator.compare(o1.charAt(index), + o2.charAt(index)) == 0) + { + if (!Character.isDigit(o1.charAt(index++))) { + numStart1 = index; + } + } + + int numCount1 = index - numStart1; + if (numCount1 > 0 || + (index < minLength && + Character.isDigit(o1.charAt(index)) && + Character.isDigit(o2.charAt(index)))) + { + // first different character is a digit + int numCount2 = numCount1; + int numStart2 = numStart1; + + numCount1 += countDigits(o1, index); + numCount2 += countDigits(o2, index); + + int numCountWithZeros1 = numCount1; + int numCountWithZeros2 = numCount2; + + while (numCount1 < numCount2) { + if (charComparator.compare(o2.charAt(numStart2), '0') != 0) { + return -1; + } + numStart2++; + numCount2--; + } + + while (numCount2 < numCount1) { + if (charComparator.compare(o1.charAt(numStart1), '0') != 0) { + return 1; + } + numStart1++; + numCount1--; + } + + // here numCount1 == numCount2; + while (numCount1-- > 0) { + int res = charComparator.compare(o1.charAt(numStart1++), + o2.charAt(numStart2++)); + if (res != 0) { + return res; + } + } + + if (numCountWithZeros1 != numCountWithZeros2) { + return (numCountWithZeros1 < numCountWithZeros2) ? -1 : 1; + } + + } + + // otherwise, compare literally + for (;; ++index) { + if (index < o1.length()) { + if (index < o2.length()) { + int res = charComparator.compare(o1.charAt(index), + o2.charAt(index)); + if (res != 0) { + return res; + } + } else { + return 1; + } + } else { + if (index < o2.length()) { + return -1; + } + return 0; + } + } + } +} diff --git a/src/sample/share/comparator/Test.java b/src/sample/share/comparator/Test.java new file mode 100644 --- /dev/null +++ b/src/sample/share/comparator/Test.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + +package comparator; + +import java.util.Arrays; +import java.util.Random; + +public class Test { + private final static Random random = new Random(); + + private static String[] source1() { + return new String[] { + "java 1", + "java 2", + "java 3", + "java 4", + "java 5", + "java 6", + "java 7", + "java 8", + "java 9", + "java 10", + "java 11", + }; + } + + private static String[] source2() { + return new String[] { + "string", + "string0", + "string00", + "string1", + "string01", + "string001", + "string2", + "string02", + "string002", + "string002.a", + "string002.a0", + "string002.a1", + "string0002", + "string0002", + }; + } + + public static void main(String[] args) throws Exception { + test(source1()); + test(source2()); + System.out.println("Okay"); + } + + private static void test(String[] strings) throws Exception { + // test sorting array of strings + String[] shuffledStrings = (String[])strings.clone(); + for (int i = 0; i < shuffledStrings.length - 1; ++i) { + int j = i + random.nextInt(shuffledStrings.length - i); + String tmp = shuffledStrings[i]; + shuffledStrings[i] = shuffledStrings[j]; + shuffledStrings[j] = tmp; + } + + Arrays.sort(shuffledStrings, new AlphaNumericStringComparator()); + for (int i = 0; i < strings.length - 1; ++i) { + if (!strings[i].equals(shuffledStrings[i])) { + throw new Exception("Wrong sorting order!"); + } + } + + // test sorting array of char-arrays + char[][] shuffledChars = new char[strings.length][]; + for (int i = 0; i < strings.length; ++i) { + shuffledChars[i] = strings[i].toCharArray(); + } + for (int i = 0; i < shuffledChars.length - 1; ++i) { + int j = i + random.nextInt(shuffledChars.length - i); + char[] tmp = shuffledChars[i]; + shuffledChars[i] = shuffledChars[j]; + shuffledChars[j] = tmp; + } + + Arrays.sort(shuffledChars, new AlphaNumericCharArrayComparator()); + for (int i = 0; i < strings.length - 1; ++i) { + if (!strings[i].equals(new String(shuffledChars[i]))) { + throw new Exception("Wrong sorting order!"); + } + } + } +}