Skip to content

Package: NumberAwareStringComparator

NumberAwareStringComparator

nameinstructionbranchcomplexitylinemethod
compare(String, String)
M: 16 C: 67
81%
M: 9 C: 11
55%
M: 6 C: 5
45%
M: 3 C: 17
85%
M: 0 C: 1
100%
getInstance()
M: 0 C: 8
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
static {...}
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%

Coverage

1: /*******************************************************************************
2: * Copyright (c) 2011-2019 EclipseSource Muenchen GmbH and others.
3: *
4: * All rights reserved. This program and the accompanying materials
5: * are made available under the terms of the Eclipse Public License 2.0
6: * which accompanies this distribution, and is available at
7: * https://www.eclipse.org/legal/epl-2.0/
8: *
9: * SPDX-License-Identifier: EPL-2.0
10: *
11: * Contributors:
12: * Lucas Koehler - initial API and implementation
13: ******************************************************************************/
14: package org.eclipse.emfforms.spi.common.sort;
15:
16: import java.math.BigInteger;
17: import java.util.Comparator;
18: import java.util.regex.Matcher;
19: import java.util.regex.Pattern;
20:
21: /**
22: * A comparator for strings that compares numbers which are part of compared string as numbers and not as strings.
23: * This allows to sort strings that are a mixture of numbers and text (e.g. house numbers) in an intuitive fashion.
24: * For instance, plain string sorting sorts 200A greater than 1000A. This comparator sorts 1000A greater than 200A.
25: *
26: * @author Lucas Koehler
27: * @since 1.20
28: *
29: */
30: public final class NumberAwareStringComparator implements Comparator<String> {
31:
32:         // First group matches zero or more non-digits. Second group matches zero or more digits
33:         private static final Pattern PATTERN = Pattern.compile("(\\D*)(\\d*)"); //$NON-NLS-1$
34:         private static NumberAwareStringComparator instance;
35:
36:         /**
37:          * @return the static {@link NumberAwareStringComparator} instance.
38:          */
39:         public static NumberAwareStringComparator getInstance() {
40:•                if (instance == null) {
41:                         instance = new NumberAwareStringComparator();
42:                 }
43:                 return instance;
44:         }
45:
46:         private NumberAwareStringComparator() {
47:                 // Static instance should be used.
48:         }
49:
50:         @Override
51:         public int compare(String o1, String o2) {
52:                 final Matcher matcher1 = PATTERN.matcher(o1);
53:                 final Matcher matcher2 = PATTERN.matcher(o2);
54:
55:                 // For our pattern Matcher::find only returns false if the end of the string was reached.
56:•                while (matcher1.find() && matcher2.find()) {
57:                         // group(1) gets the results matched by \\D* (non-digits)
58:                         final int wordCompare = matcher1.group(1).compareToIgnoreCase(matcher2.group(1));
59:•                        if (wordCompare != 0) {
60:                                 return wordCompare;
61:                         }
62:
63:                         // group(2) gets the results matched by \\d* (digits)
64:                         final String numberString1 = matcher1.group(2);
65:                         final String numberString2 = matcher2.group(2);
66:
67:•                        if (numberString1.isEmpty()) {
68:                                 // Empty string is smaller than any other string
69:•                                return numberString2.isEmpty() ? 0 : -1;
70:•                        } else if (numberString2.isEmpty()) {
71:                                 return 1;
72:                         }
73:
74:                         final BigInteger number1 = new BigInteger(numberString1);
75:                         final BigInteger number2 = new BigInteger(numberString2);
76:                         final int numberCompare = number1.compareTo(number2);
77:•                        if (numberCompare != 0) {
78:                                 return numberCompare;
79:                         }
80:                 }
81:
82:•                if (matcher1.hitEnd() && matcher2.hitEnd()) {
83:                         return 0;
84:                 }
85:•                return matcher1.hitEnd() ? -1 : 1;
86:         }
87:
88: }