/** * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.car.voicecontrol; import android.util.Log; /** * Utility string comparison methods */ public final class StringUtils { private static final String TAG = "Mica.StringUtils"; // This is a utility class private StringUtils() {} /** * Returns the minimum edit distance between one source string and a set of possible * target strings */ public static int getMinDistance(String source, String... targets) { int d = Integer.MAX_VALUE; for (String t : targets) { if (t != null) { int newD = getDistance(source, t); d = Math.min(d, newD); Log.d(TAG, "Distance between: '" + source + "' and '" + t + "': " + newD); } } return d; } // // Copied from https://commons.apache.org/proper/commons-lang/javadocs/api-2.5/src-html/org/apache/commons/lang/StringUtils.html // private static int getDistance(String s, String t) { int n = s.length(); int m = t.length(); if (n == 0) { return m; } else if (m == 0) { return n; } if (n > m) { String tmp = s; s = t; t = tmp; n = m; m = t.length(); } int[] p = new int[n + 1]; int[] d = new int[n + 1]; int[] _d; int i, j, cost; char t_j; for (i = 0; i <= n; i++) { p[i] = i; } for (j = 1; j <= m; j++) { t_j = t.charAt(j - 1); d[0] = j; for (i = 1; i <= n; i++) { cost = s.charAt(i - 1) == t_j ? 0 : 1; d[i] = Math.min(Math.min(d[i - 1] + 1, p[i] + 1), p[i - 1] + cost); } _d = p; p = d; d = _d; } return p[n]; } // // end of https://commons.apache.org/proper/commons-lang/javadocs/api-2.5/src-html/org/apache/commons/lang/StringUtils.html // // // The section below has been copied from // http://commons.apache.org/proper/commons-codec/apidocs/src-html/org/apache/commons/codec/language/Soundex.html // private static final char SILENT_MARKER = '-'; private static final char[] US_ENGLISH_MAPPING_STRING = "01230120022455012623010202" .toCharArray(); private static char soundexMap(final char ch) { final int index = ch - 'A'; if (index < 0 || index >= US_ENGLISH_MAPPING_STRING.length) { return SILENT_MARKER; } return US_ENGLISH_MAPPING_STRING[index]; } private static String soundexClean(String str) { if (str == null || str.length() == 0) { return str; } int len = str.length(); char[] chars = new char[len]; int count = 0; for (int i = 0; i < len; i++) { if (Character.isLetter(str.charAt(i))) { chars[count++] = str.charAt(i); } } return new String(chars, 0, count).toUpperCase(java.util.Locale.ENGLISH); } /** * Encodes a string into a Soundex value. Soundex is an encoding used to relate similar names, * but can also be used as a general purpose scheme to find word with similar phonemes. */ public static String soundex(String str) { if (str == null) { return null; } str = soundexClean(str); if (str.length() == 0) { return str; } final char[] out = {'0', '0', '0', '0'}; int count = 0; final char first = str.charAt(0); out[count++] = first; char lastDigit = soundexMap(first); for (int i = 1; i < str.length() && count < out.length; i++) { final char ch = str.charAt(i); if (ch == 'H' || ch == 'W') { continue; } final char digit = soundexMap(ch); if (digit == SILENT_MARKER) { continue; } if (digit != '0' && digit != lastDigit) { out[count++] = digit; } lastDigit = digit; } return new String(out); } // // End of // http://commons.apache.org/proper/commons-codec/apidocs/src-html/org/apache/commons/codec/language/Soundex.html // }