001package org.unix4j.util.sort; 002 003import org.unix4j.util.StringUtil; 004 005import java.text.DateFormatSymbols; 006import java.util.Comparator; 007import java.util.Locale; 008 009/** 010 * A comparator Months: (unknown) < 'JAN' < ... < 'DEC'. The current locale 011 * determines the month spellings. 012 */ 013public class MonthStringComparator implements Comparator<CharSequence> { 014 015 /** 016 * The instance for the default locale returned by {@link #getInstance()}. 017 */ 018 private static final MonthStringComparator DEFAULT_INSTANCE = new MonthStringComparator(); 019 020 /** 021 * Returns the instance for the default locale. 022 * 023 * @see Locale#getDefault() 024 */ 025 public static MonthStringComparator getInstance() { 026 return DEFAULT_INSTANCE; 027 } 028 029 /** 030 * Returns an instance for the specified locale. 031 */ 032 public static MonthStringComparator getInstance(Locale locale) { 033 return new MonthStringComparator(locale); 034 } 035 036 private final String[] months; 037 private final String[] shortMonths; 038 039 /** 040 * Private constructor used to create the {@link #DEFAULT_INSTANCE}. 041 */ 042 private MonthStringComparator() { 043 this(DateFormatSymbols.getInstance()); 044 } 045 046 /** 047 * Private constructor used by {@link #getInstance(Locale)}. 048 */ 049 private MonthStringComparator(Locale locale) { 050 this(DateFormatSymbols.getInstance(locale)); 051 } 052 053 /** 054 * Constructor with date symbols. 055 * 056 * @param symbols 057 * the date symbols 058 */ 059 public MonthStringComparator(DateFormatSymbols symbols) { 060 this.months = symbols.getMonths(); 061 this.shortMonths = symbols.getShortMonths(); 062 } 063 064 @Override 065 public int compare(CharSequence s1, CharSequence s2) { 066 final int start1 = StringUtil.findStartTrimWhitespace(s1); 067 final int end1 = StringUtil.findEndTrimWhitespace(s1); 068 final int start2 = StringUtil.findStartTrimWhitespace(s2); 069 final int end2 = StringUtil.findEndTrimWhitespace(s2); 070 final int month1 = month(s1, start1, end1); 071 final int month2 = month(s2, start2, end2); 072 return Integer.compare(month1, month2); 073 } 074 075 private final int month(CharSequence s, int start, int end) { 076 int m = month(months, s, start, end); 077 return m >= 0 ? m : month(shortMonths, s, start, end); 078 } 079 080 private static int month(String[] months, CharSequence s, int start, int end) { 081 for (int i = 0; i < months.length; i++) { 082 final String month = months[i]; 083 if (!equalsIgnoreCase(month, s, start, end)) { 084 continue; 085 } 086 return i; 087 } 088 return -1; 089 } 090 091 private static final boolean equalsIgnoreCase(String s1, CharSequence s2, int start, int end) { 092 if (end - start != s1.length()) { 093 return false; 094 } 095 for (int i = start; i < end; i++) { 096 if (!equalsIgnoreCase(s1.charAt(i - start), s2.charAt(i))) { 097 return false; 098 } 099 } 100 return true; 101 } 102 private static final boolean equalsIgnoreCase(char ch1, char ch2) { 103 return Character.toUpperCase(ch1) == Character.toUpperCase(ch2); 104 } 105}