package io.blobkeeper.common.util;
import java.util.Comparator;
/*
* Copyright (C) 2015 by Denis M. Gabaydulin
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
* This is an updated version with enhancements made by Daniel Migowski,
* Andre Bogus, and David Koelle.
*/
public class AlphaNumComparator implements Comparator<String> {
public AlphaNumComparator() {
}
@Override
public int compare(String o1, String o2) {
if (o1 == null || o2 == null) {
return 0;
}
int thisMarker = 0;
int thatMarker = 0;
int s1Length = o1.length();
int s2Length = o2.length();
while (thisMarker < s1Length && thatMarker < s2Length) {
String thisChunk = getChunk(o1, s1Length, thisMarker);
thisMarker += thisChunk.length();
String thatChunk = getChunk(o2, s2Length, thatMarker);
thatMarker += thatChunk.length();
// If both chunks contain numeric characters, sort them numerically
int result = 0;
if (isDigit(thisChunk.charAt(0)) && isDigit(thatChunk.charAt(0))) {
// Simple chunk comparison by length.
int thisChunkLength = thisChunk.length();
result = thisChunkLength - thatChunk.length();
// If equal, the first different number counts
if (result == 0) {
for (int i = 0; i < thisChunkLength; i++) {
result = thisChunk.charAt(i) - thatChunk.charAt(i);
if (result != 0) {
return result;
}
}
}
} else {
result = thisChunk.compareTo(thatChunk);
}
if (result != 0)
return result;
}
return s1Length - s2Length;
}
private boolean isDigit(char ch) {
return ch >= 48 && ch <= 57;
}
/**
* Length of string is passed in for improved efficiency (only need to calculate it once)
*/
private String getChunk(String s, int slength, int marker) {
StringBuilder chunk = new StringBuilder();
char c = s.charAt(marker);
chunk.append(c);
marker++;
if (isDigit(c)) {
while (marker < slength) {
c = s.charAt(marker);
if (!isDigit(c))
break;
chunk.append(c);
marker++;
}
} else {
while (marker < slength) {
c = s.charAt(marker);
if (isDigit(c))
break;
chunk.append(c);
marker++;
}
}
return chunk.toString();
}
}