001package org.unix4j.util.sort; 002 003import java.util.Comparator; 004 005import org.unix4j.util.StringUtil; 006 007/** 008 * Comparison based on {@link Double} floating point numbers. This 009 * allows floating point numbers to be specified in scientific notation, 010 * like 1.0e-34 and 10e100 using {@link Double#parseDouble(String)}. Leading 011 * and trailing strings are ignored. If the string is not a valid number, it is 012 * treated as {@link Double#NaN} during the comparison. 013 */ 014public class ScientificNumberStringComparator implements Comparator<CharSequence> { 015 016 /** 017 * The singleton instance. 018 */ 019 public static final ScientificNumberStringComparator INSTANCE = new ScientificNumberStringComparator(); 020 021 /** 022 * Private constructor for the singleton {@link #INSTANCE}. 023 */ 024 private ScientificNumberStringComparator () { 025 super(); 026 } 027 028 @Override 029 public int compare(CharSequence s1, CharSequence s2) { 030 final int start1 = StringUtil.findStartTrimWhitespace(s1); 031 final int end1 = StringUtil.findEndTrimWhitespace(s1); 032 final int start2 = StringUtil.findStartTrimWhitespace(s2); 033 final int end2 = StringUtil.findEndTrimWhitespace(s2); 034 final String str1 = s1.subSequence(start1, end1).toString(); 035 final String str2 = s2.subSequence(start2, end2).toString(); 036 final double dbl1 = parseDouble(str1); 037 final double dbl2 = parseDouble(str2); 038 final boolean isNan1 = Double.isNaN(dbl1); 039 final boolean isNan2 = Double.isNaN(dbl2); 040 if (isNan1 || isNan2) { 041 final boolean isNonDouble1 = isNan1 && !"NaN".equals(str1); 042 final boolean isNonDouble2 = isNan2 && !"NaN".equals(str2); 043 if (isNonDouble1 && isNonDouble2) { 044 return str1.compareTo(str2); 045 } 046 if (isNonDouble1) return -1; 047 if (isNonDouble2) return 1; 048 } 049 return Double.compare(dbl1, dbl2); 050 } 051 private static double parseDouble(String s) { 052 try { 053 return Double.parseDouble(s); 054 } catch (NumberFormatException e) { 055 return Double.NaN; 056 } 057 } 058}