View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.codec.language;
19  
20  import java.util.Locale;
21  
22  import org.apache.commons.codec.EncoderException;
23  import org.apache.commons.codec.StringEncoder;
24  
25  /**
26   * Utility methods for {@link Soundex} and {@link RefinedSoundex} classes.
27   * <p>
28   * This class is immutable and thread-safe.
29   * </p>
30   *
31   * @since 1.3
32   */
33  final class SoundexUtils {
34  
35      /**
36       * Cleans up the input string before Soundex processing by only returning upper case letters.
37       *
38       * @param str The String to clean.
39       * @return A clean String.
40       */
41      static String clean(final String str) {
42          if (isEmpty(str)) {
43              return str;
44          }
45          final int len = str.length();
46          final char[] chars = new char[len];
47          int count = 0;
48          for (int i = 0; i < len; i++) {
49              if (Character.isLetter(str.charAt(i))) {
50                  chars[count++] = str.charAt(i);
51              }
52          }
53          if (count == len) {
54              return str.toUpperCase(Locale.ENGLISH);
55          }
56          return new String(chars, 0, count).toUpperCase(Locale.ENGLISH);
57      }
58  
59      /**
60       * Encodes the Strings and returns the number of characters in the two encoded Strings that are the same.
61       * <ul>
62       * <li>For Soundex, this return value ranges from 0 through 4: 0 indicates little or no similarity, and 4 indicates strong similarity or identical
63       * values.</li>
64       * <li>For refined Soundex, the return value can be greater than 4.</li>
65       * </ul>
66       *
67       * @param encoder The encoder to use to encode the Strings.
68       * @param s1      A String that will be encoded and compared.
69       * @param s2      A String that will be encoded and compared.
70       * @return The number of characters in the two Soundex encoded Strings that are the same.
71       * @see #differenceEncoded(String,String)
72       * @see <a href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/tsqlref/ts_de-dz_8co5.asp"> MS T-SQL DIFFERENCE</a>
73       * @throws EncoderException Thrown if an error occurs encoding one of the strings.
74       */
75      static int difference(final StringEncoder encoder, final String s1, final String s2) throws EncoderException {
76          return differenceEncoded(encoder.encode(s1), encoder.encode(s2));
77      }
78  
79      /**
80       * Returns the number of characters in the two Soundex encoded Strings that are the same.
81       * <ul>
82       * <li>For Soundex, this return value ranges from 0 through 4: 0 indicates little or no similarity, and 4 indicates strong similarity or identical
83       * values.</li>
84       * <li>For refined Soundex, the return value can be greater than 4.</li>
85       * </ul>
86       *
87       * @param es1 An encoded String.
88       * @param es2 An encoded String.
89       * @return The number of characters in the two Soundex encoded Strings that are the same.
90       * @see <a href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/tsqlref/ts_de-dz_8co5.asp"> MS T-SQL DIFFERENCE</a>
91       */
92      static int differenceEncoded(final String es1, final String es2) {
93          if (es1 == null || es2 == null) {
94              return 0;
95          }
96          final int lengthToMatch = Math.min(es1.length(), es2.length());
97          int diff = 0;
98          for (int i = 0; i < lengthToMatch; i++) {
99              if (es1.charAt(i) == es2.charAt(i)) {
100                 diff++;
101             }
102         }
103         return diff;
104     }
105 
106     /**
107      * Tests if a CharSequence is empty ("") or null.
108      *
109      * <pre>
110      * StringUtils.isEmpty(null)      = true
111      * StringUtils.isEmpty("")        = true
112      * StringUtils.isEmpty(" ")       = false
113      * StringUtils.isEmpty("bob")     = false
114      * StringUtils.isEmpty("  bob  ") = false
115      * </pre>
116      *
117      * @param cs The CharSequence to check, may be null.
118      * @return {@code true} if the CharSequence is empty or null.
119      */
120     static boolean isEmpty(final CharSequence cs) {
121         return cs == null || cs.length() == 0;
122     }
123 }