[10] RFR 8134512 : provide Alpha-Numeric (logical) Comparator

Ivan Gerasimov ivan.gerasimov at oracle.com
Fri Jul 28 16:25:52 UTC 2017

Hi Peter!

Thank a lot for looking into this!

On 7/28/17 7:32 AM, Peter Levart wrote:
> Hi Ivan,
> In the light of what Stuart Marks wrote, then what do you think about 
> a parameterized comparator (would be sub-optimal, I know) where one 
> would supply
> 2 Comparator(s) which would be used to compare Ax and Nx sub-sequences 
> respectively as described below...
Yes.  Inspired by what Stuart suggested I made a draft of such a 
comparator (see below).
It works, but as you've said it's not that efficient (mostly due to 
expensive substrings) and a bit harder to use in a simple case.
Now I need to think about how to combine two approaches.

> For Nx sub-sequences, one would need a comparator comparing the 
> reversed sequence lexicographically,
I'm not sure I understand why they need to be reversed.
> but for Ax sub-sequences, one could choose from a plethora of 
> case-(in)sensitive comparator(s) and collators already available on 
> the platform.
Yes. In the example below I used compareToIgnoreCase to compare alpha 


class MyComparator implements Comparator<String> {Comparator<String> 
alphaCmp;Comparator<String> numCmp;MyComparator(Comparator<String> 
alphaCmp,Comparator<String> numCmp) {this.alphaCmp = 
alphaCmp;this.numCmp = numCmp;}boolean skipLeadingZeroes(String s, int 
len) {for (int i = 0; i < len ; ++i) {if (Character.digit(s.charAt(i), 
10) != 0)return false;}return true;}@Override public int compare(String 
o1, String o2) {Supplier<String> s1 = new 
NumberSlicer(o1);Supplier<String> s2 = new NumberSlicer(o2);while (true) 
{// alpha part String ss1 = s1.get();String ss2 = s2.get();int cmp = 
alphaCmp.compare(ss1, ss2);if (cmp != 0) return cmp;if (ss1.length() == 
0) return 0;// numeric part ss1 = s1.get();ss2 = s2.get();int len1 = 
ss1.length();int len2 = ss2.length();int dlen = len1 - len2;if (dlen > 
0) {if (!skipLeadingZeroes(ss1, dlen))return 1;ss1 = ss1.substring(dlen, 
len1);} else if (dlen < 0) {if (!skipLeadingZeroes(ss2, -dlen))return 
-1;ss2 = ss2.substring(-dlen, len2);}cmp = numCmp.compare(ss1, ss2);if 
(cmp != 0) return cmp;if (dlen != 0) return dlen;}}static class 
NumberSlicer implements Supplier<String> {private String 
sequence;private boolean expectNumber = false;private int index = 
0;NumberSlicer(String s) {sequence = s;}@Override public String get() 
{int start = index, end = start, len = sequence.length() - start;for (; 
len > 0; ++end, --len) {if (Character.isDigit(sequence.charAt(end)) ^ 
expectNumber)break;}expectNumber = !expectNumber;return 
sequence.substring(start, index = end);}}}------------Here how it is 
invoked with case-insensitive comparator:Arrays.sort(str,new 

simple test results for case insensitive sorting:java 1java 1 javajava 1 
JAVAJava 2JAVA 5jaVA 6.1java 10java 10 v 13Java 10 v 013Java 10 v 
000013java 10 v 113Java 2017Java 2017Java 20017Java 200017Java 
2000017Java 20000017Java 20000017Java 200000017With kind regards, Ivan

More information about the core-libs-dev mailing list