1 /* 2 * Copyright (c) 2017 Helmut Neemann 3 * Use of this source code is governed by the GPL v3 license 4 * that can be found in the LICENSE file. 5 */ 6 package de.neemann.digital.draw.library; 7 8 import java.util.Comparator; 9 10 import static java.lang.Character.isDigit; 11 12 /** 13 * String comparator. 14 * If the string contains a digit, the numbers are taken to compare the two strings. 15 * Used to ensure the 74xx components appear in the correct numerical order instead of lexical order. 16 */ 17 public final class NumStringComparator implements Comparator<String> { 18 19 private static final class InstanceHolder { 20 private static final NumStringComparator INSTANCE = new NumStringComparator(); 21 } 22 23 /** 24 * Returns a comparator instance 25 * 26 * @return the singleton instance 27 */ getInstance()28 public static NumStringComparator getInstance() { 29 return InstanceHolder.INSTANCE; 30 } 31 NumStringComparator()32 private NumStringComparator() { 33 } 34 35 @Override compare(String a, String b)36 public int compare(String a, String b) { 37 return compareStr(a, b); 38 } 39 40 /** 41 * Compare two strings 42 * 43 * @param a a string 44 * @param b a string 45 * @return the comparison result 46 */ compareStr(String a, String b)47 public static int compareStr(String a, String b) { 48 int pa = 0; 49 int pb = 0; 50 while (true) { 51 final boolean ae = pa == a.length(); 52 final boolean be = pb == b.length(); 53 if (ae && be) return 0; 54 else if (ae) return -1; 55 else if (be) return 1; 56 57 char ca = Character.toLowerCase(a.charAt(pa)); 58 char cb = Character.toLowerCase(b.charAt(pb)); 59 60 if (isDigit(ca) && isDigit(cb)) { 61 ParseNumber da = new ParseNumber(a, pa); 62 ParseNumber db = new ParseNumber(b, pb); 63 int c = Integer.compare(da.num, db.num); 64 if (c != 0) 65 return c; 66 else { 67 pa = da.p; 68 pb = db.p; 69 } 70 } else { 71 int c = Character.compare(ca, cb); 72 if (c != 0) { 73 return c; 74 } else { 75 pa++; 76 pb++; 77 } 78 } 79 } 80 } 81 82 private static final class ParseNumber { 83 private int num; 84 private int p; 85 ParseNumber(String a, int sp)86 private ParseNumber(String a, int sp) { 87 p = sp; 88 while (p < a.length() && isDigit(a.charAt(p))) { 89 num = num * 10 + (a.charAt(p) - '0'); 90 p++; 91 } 92 } 93 } 94 95 } 96