source: josm/trunk/src/org/openstreetmap/josm/tools/AlphanumComparator.java@ 14012

Last change on this file since 14012 was 13836, checked in by Don-vip, 6 years ago

fix #13889 - Make preset searchs ignore accents

  • Property svn:eol-style set to native
File size: 5.4 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.tools;
3
4/*
5 * The Alphanum Algorithm is an improved sorting algorithm for strings
6 * containing numbers. Instead of sorting numbers in ASCII order like a standard
7 * sort, this algorithm sorts numbers in numeric order.
8 *
9 * The Alphanum Algorithm is discussed at http://www.DaveKoelle.com
10 *
11 * Released under the MIT License - https://opensource.org/licenses/MIT
12 *
13 * Copyright 2007-2017 David Koelle
14 *
15 * Permission is hereby granted, free of charge, to any person obtaining
16 * a copy of this software and associated documentation files (the "Software"),
17 * to deal in the Software without restriction, including without limitation
18 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
19 * and/or sell copies of the Software, and to permit persons to whom the
20 * Software is furnished to do so, subject to the following conditions:
21 *
22 * The above copyright notice and this permission notice shall be included
23 * in all copies or substantial portions of the Software.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
28 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
29 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
30 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
31 * USE OR OTHER DEALINGS IN THE SOFTWARE.
32 */
33import java.io.Serializable;
34import java.text.Collator;
35import java.util.Comparator;
36
37/**
38 * The Alphanum Algorithm is an improved sorting algorithm for strings
39 * containing numbers: Instead of sorting numbers in ASCII order like a standard
40 * sort, this algorithm sorts numbers in numeric order.
41 *
42 * The Alphanum Algorithm is discussed at http://www.DaveKoelle.com
43 *
44 * This is an updated version with enhancements made by Daniel Migowski, Andre
45 * Bogus, David Koelle and others.
46 *
47 */
48public final class AlphanumComparator implements Comparator<String>, Serializable {
49
50 private static final long serialVersionUID = 1L;
51
52 private static final AlphanumComparator INSTANCE = new AlphanumComparator();
53
54 /**
55 * Replies the unique instance.
56 * @return the unique instance
57 */
58 public static AlphanumComparator getInstance() {
59 return INSTANCE;
60 }
61
62 /**
63 * Constructs a new Alphanum Comparator.
64 */
65 private AlphanumComparator() {
66 }
67
68 /**
69 * Returns an alphanum chunk.
70 * Length of string is passed in for improved efficiency (only need to calculate it once).
71 * @param s string
72 * @param slength string length
73 * @param marker position
74 * @return alphanum chunk found at given position
75 */
76 private static String getChunk(String s, int slength, int marker) {
77 StringBuilder chunk = new StringBuilder();
78 char c = s.charAt(marker);
79 chunk.append(c);
80 marker++;
81 if (Character.isDigit(c)) {
82 while (marker < slength) {
83 c = s.charAt(marker);
84 if (!Character.isDigit(c)) {
85 break;
86 }
87 chunk.append(c);
88 marker++;
89 }
90 } else {
91 while (marker < slength) {
92 c = s.charAt(marker);
93 if (Character.isDigit(c)) {
94 break;
95 }
96 chunk.append(c);
97 marker++;
98 }
99 }
100 return chunk.toString();
101 }
102
103 @Override
104 public int compare(String s1, String s2) {
105 if (s1 == null && s2 == null) {
106 return 0;
107 } else if (s1 == null) {
108 return -1;
109 } else if (s2 == null) {
110 return 1;
111 }
112
113 int thisMarker = 0;
114 int thatMarker = 0;
115 int s1Length = s1.length();
116 int s2Length = s2.length();
117
118 while (thisMarker < s1Length && thatMarker < s2Length) {
119 String thisChunk = getChunk(s1, s1Length, thisMarker);
120 thisMarker += thisChunk.length();
121
122 String thatChunk = getChunk(s2, s2Length, thatMarker);
123 thatMarker += thatChunk.length();
124
125 // If both chunks contain numeric characters, sort them numerically
126 int result;
127 if (Character.isDigit(thisChunk.charAt(0)) && Character.isDigit(thatChunk.charAt(0))) {
128 // Simple chunk comparison by length.
129 int thisChunkLength = thisChunk.length();
130 result = thisChunkLength - thatChunk.length();
131 // If equal, the first different number counts
132 if (result == 0) {
133 for (int i = 0; i < thisChunkLength; i++) {
134 result = thisChunk.charAt(i) - thatChunk.charAt(i);
135 if (result != 0) {
136 return result;
137 }
138 }
139 }
140 } else {
141 // Instantiate the collator
142 Collator compareOperator = Collator.getInstance();
143 // Compare regardless of accented letters
144 compareOperator.setStrength(Collator.SECONDARY);
145 result = compareOperator.compare(thisChunk, thatChunk);
146 }
147
148 if (result != 0) {
149 return result;
150 }
151 }
152
153 return s1Length - s2Length;
154 }
155}
Note: See TracBrowser for help on using the repository browser.