/**
*
* UptimeComparator : A comparator to compare strings containing
* numbers in the natural order instead of the ASCII order.
*/
class UptimeComparator implements Comparator {
private static final String NUMBER_PATTERN = "(\\d+)";
@Override
/**
* Expecting the uptime string in the below formats only.
* Otherwise this method may not work according to expectation !!!
* 1) 3 min
* 2) 4:48 hour
* 3) 10 days 4:48 hours
* 4) 10 days 3 min
*/
public int compare(String arg0, String arg1) {
// To avoid comparison issues, due to white spaces, remove excess spaces
arg0 = arg0.replaceAll("[\\s]+", " ");
arg1 = arg1.replaceAll("[\\s]+", " ");
/**
* Time mentioned in minute is always smaller than
* that mentioned in days or hours
*/
if ((arg1.matches("[\\d]+ min")
&& arg0.matches("[\\d]+ days [\\d]+:[\\d]+ hour"))
|| (arg1.matches("[\\d]+ min")
&& arg0.matches("[\\d]+ days [\\d]+ min"))
|| (arg1.matches("[\\d]+ min")
&& arg0.matches("[\\d]+:[\\d]+ hour"))) {
return 1;
}
if ((arg0.matches("[\\d]+ min")
&& arg1.matches("[\\d]+ days [\\d]+:[\\d]+ hour"))
|| (arg0.matches("[\\d]+ min")
&& arg1.matches("[\\d]+ days [\\d]+ min"))
|| (arg0.matches("[\\d]+ min")
&& arg1.matches("[\\d]+:[\\d]+ hour"))) {
return -1;
}
/**
* Time mentioned in hours is always smaller than
* that mentioned in days.
*/
if ((arg1.matches("[\\d]+:[\\d]+ hour")
&& arg0.matches("[\\d]+ days [\\d]+:[\\d]+ hour"))
|| (arg1.matches("[\\d]+:[\\d]+ hour")
&& arg0.matches("[\\d]+ days [\\d]+ min"))) {
return 1;
}
if ((arg0.matches("[\\d]+:[\\d]+ hour")
&& arg1.matches("[\\d]+ days [\\d]+:[\\d]+ hour"))
|| (arg0.matches("[\\d]+:[\\d]+ hour")
&& arg1.matches("[\\d]+ days [\\d]+ min"))) {
return -1;
}
/**
* If both days are not equal, compare only the days.
*/
if((arg0.matches("[\\d]+ days ([\\w]|[\\W])*"))
&& (arg1.matches("[\\d]+ days ([\\w]|[\\W])*"))){
String day1 = arg0.split("[\\s]+")[0];
String day2 = arg1.split("[\\s]+")[0];
if (!day1.equals(day2) && day1.matches(NUMBER_PATTERN)
&& day2.matches(NUMBER_PATTERN)) {
return (int)(Double.parseDouble(day1) - Double.parseDouble(day2));
}
}
/**
* If both days are equal....
* Eg. "X days Y min" is always less than "X days P:Q hour"
*/
if ((arg1.matches("[\\d]+ days [\\d]+ min")
&& arg0.matches("[\\d]+ days [\\d]+:[\\d]+ hour"))) {
return 1;
}
if ((arg0.matches("[\\d]+ days [\\d]+ min")
&& arg1.matches("[\\d]+ days [\\d]+:[\\d]+ hour"))) {
return -1;
}
/**
* If both string are identical, compare based on the integer in them.
*/
return compareStringWithNumber(arg0, arg1);
}
/**
* Compare two strings with numbers in the natural order.
* compareStringWithNumber.
*
* @param str1
* @param str2
* @return
*/
public int compareStringWithNumber(String str1, String str2) {
if (str1 == null || str2 == null) {
return 0;
}
List split1 = split(str1);
List split2 = split(str2);
int diff = 0;
for (int i = 0; diff == 0 && i < split1.size() && i < split2.size(); i++) {
String token1 = split1.get(i);
String token2 = split2.get(i);
if (token1.matches(NUMBER_PATTERN)
&& token2.matches(NUMBER_PATTERN)) {
diff = (int) Math.signum(Double.parseDouble(token1)
- Double.parseDouble(token2));
} else {
diff = token1.compareToIgnoreCase(token2);
}
}
if (diff != 0) {
return diff;
}
return split1.size() - split2.size();
}
/**
* Splits a string into strings and number tokens.
*/
private List split(String s) {
List list = new ArrayList();
Scanner scanner = new Scanner(s);
int index = 0;
String num = null;
while ((num = scanner.findInLine(NUMBER_PATTERN)) != null) {
int indexOfNumber = s.indexOf(num, index);
if (indexOfNumber > index) {
list.add(s.substring(index, indexOfNumber).trim());
}
list.add(num);
index = indexOfNumber + num.length();
}
if (index < s.length()) {
list.add(s.substring(index));
}
return list;
}