package tc.oc.commons.core; /** * Direct port of the JavaScript LiquidMetal. https://github.com/rmm5t/liquidmetal * * @author Steve Anton */ public class LiquidMetal { public static final double SCORE_NO_MATCH = 0.0; public static final double SCORE_MATCH = 1.0; public static final double SCORE_TRAILING = 0.8; public static final double SCORE_TRAILING_BUT_STARTED = 0.9; public static final double SCORE_BUFFER = 0.85; public static double score(String string, String abbreviation) { if (abbreviation.length() == 0) return SCORE_TRAILING; if (abbreviation.length() > string.length()) return SCORE_NO_MATCH; double[] scores = buildScoreArray(string, abbreviation); // complete miss: if (scores == null) { return 0; } double sum = 0.0; for (double score : scores) { sum += score; } return (sum / scores.length); } private static double[] buildScoreArray(String string, String abbreviation) { double[] scores = new double[string.length()]; String lower = string.toLowerCase(); String chars = abbreviation.toLowerCase(); int lastIndex = -1; boolean started = false; for (int i = 0; i < chars.length(); i++) { char c = chars.charAt(i); int index = lower.indexOf(c, lastIndex + 1); if (index == -1) return null; // signal no match if (index == 0) started = true; if (isNewWord(string, index)) { scores[index - 1] = 1.0; fillArray(scores, SCORE_BUFFER, lastIndex + 1, index - 1); } else if (isUpperCase(string, index)) { fillArray(scores, SCORE_BUFFER, lastIndex + 1, index); } else { fillArray(scores, SCORE_NO_MATCH, lastIndex + 1, index); } scores[index] = SCORE_MATCH; lastIndex = index; } double trailingScore = started ? SCORE_TRAILING_BUT_STARTED : SCORE_TRAILING; fillArray(scores, trailingScore, lastIndex + 1, scores.length); return scores; } private static boolean isNewWord(String string, int index) { if (index == 0) return false; char c = string.charAt(index - 1); return (c == ' ' || c == '\t'); } private static void fillArray(double[] array, double value, int from, int to) { for (int i = from; i < to; i++) { array[i] = value; } } private static boolean isUpperCase(String string, int index) { char c = string.charAt(index); return ('A' <= c && c <= 'Z'); } }