83 lines
2.6 KiB
Java
83 lines
2.6 KiB
Java
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');
|
|
}
|
|
}
|