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