001package jmri.util; 002 003import java.util.Comparator; 004import java.util.regex.Pattern; 005 006/** 007 * A comparator for mixed Strings containing a mix of words and numbers: "ATSF 123", 008 * "CN 100B", etc. 009 * 010 * Regex implementation first, but that might be too slow 011 */ 012 013public class ChunkyNumbersComparator implements Comparator<String> { 014 015 @Override 016 public int compare(String s1, String s2) { 017 018 var m1 = sortPattern.matcher(s1); 019 var m2 = sortPattern.matcher(s2); 020 021 if (!m1.find() || !m2.find()) { 022 log.warn("Failed to parse '{}' '{}'", s1, s2); 023 return s1.compareTo(s2); 024 } 025 026 // note increment by 2, because of two cases inside the loop 027 for (int index = 1; index < 6; index = index + 2) { 028 029 // check first alpha group 030 String g1 = m1.group(index); 031 String g2 = m2.group(index); 032 int len1 = g1.length(); 033 int len2 = g2.length(); 034 035 // Is there at least one letter group? 036 if (len1 > 0 || len2 > 0) { 037 int result = g1.compareTo(g2); 038 if (result !=0) { 039 return result; 040 } 041 } 042 043 // check number group 044 g1 = m1.group(index+1); 045 g2 = m2.group(index+1); 046 047 boolean g1e = g1.isEmpty(); 048 boolean g2e = g2.isEmpty(); 049 if (g1e && g2e) { 050 // no match, so done (can't be another letter group, would have been picked up above) 051 return 0; 052 } 053 if (g1e) { 054 return -1; 055 } 056 if (g2e) { 057 return +1; 058 } 059 060 // Here an number group in each input, parse as numbers and compare 061 Long v1; 062 Long v2; 063 try { 064 v1 = Long.valueOf(g1); 065 v2 = Long.valueOf(g2); 066 } catch (NumberFormatException e1) { 067 log.warn("Comparison should not have reached here with {} {}", g1, g2); 068 return s1.compareTo(s2); 069 } 070 // check for parsed numbers 071 int result = v1.compareTo(v2); 072 if (result !=0) { 073 return result; 074 } 075 076 // reached here, go around again 077 } 078 // reached here, didn't find a difference 079 return 0; 080 } 081 082 static final Pattern sortPattern = Pattern.compile("([^0-9]*)([0-9]*)([^0-9]*)([0-9]*)([^0-9]*)([0-9]*)"); 083 084 //private final boolean isDigit(char ch) { 085 // return (('0' <= ch) && (ch <= '9')); 086 //} 087 088 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ChunkyNumbersComparator.class); 089 090}