13 changed files with 9531 additions and 11117 deletions
@ -1,108 +0,0 @@
@@ -1,108 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2008 the original author or authors. |
||||
* |
||||
* 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 org.springframework.expression.spel.ast; |
||||
|
||||
import org.antlr.runtime.Token; |
||||
import org.springframework.expression.EvaluationException; |
||||
import org.springframework.expression.spel.ExpressionState; |
||||
import org.springframework.expression.spel.SpelException; |
||||
|
||||
/** |
||||
* The distanceto operator uses an implementation of the levenshtein distance measurement for determining the 'edit |
||||
* distance' between two strings (the two operands to distanceto). http://en.wikipedia.org/wiki/Levenshtein_distance
|
||||
* |
||||
* @author Andy Clement |
||||
*/ |
||||
public class OperatorDistanceTo extends Operator { |
||||
|
||||
private final static boolean DEBUG = false; |
||||
|
||||
public OperatorDistanceTo(Token payload) { |
||||
super(payload); |
||||
} |
||||
|
||||
@Override |
||||
public String getOperatorName() { |
||||
return "distanceto"; |
||||
} |
||||
|
||||
@Override |
||||
public Object getValue(ExpressionState state) throws EvaluationException { |
||||
try { |
||||
Object left = getLeftOperand().getValue(state); |
||||
Object right = getRightOperand().getValue(state); |
||||
return computeDistanceTo((String) left, (String) right); |
||||
} catch (SpelException ee) { |
||||
throw ee; |
||||
} |
||||
} |
||||
|
||||
private int computeDistanceTo(String from, String to) { |
||||
if (from.equals(to)) |
||||
return 0; |
||||
int[][] d = new int[from.length() + 1][to.length() + 1]; |
||||
|
||||
for (int i = 0; i <= from.length(); i++) |
||||
d[i][0] = i; |
||||
|
||||
for (int j = 0; j <= to.length(); j++) |
||||
d[0][j] = j; |
||||
|
||||
for (int i = 1; i <= from.length(); i++) { |
||||
for (int j = 1; j <= to.length(); j++) { |
||||
int cost; |
||||
if (from.charAt(i - 1) == to.charAt(j - 1)) |
||||
cost = 0; |
||||
else |
||||
cost = 1; |
||||
d[i][j] = min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost);// del,ins,subst
|
||||
|
||||
} |
||||
} |
||||
if (DEBUG) { |
||||
// Display the table of values
|
||||
System.out.print(" "); |
||||
for (int j = 0; j < from.length(); j++) { |
||||
System.out.print(from.charAt(j) + " "); |
||||
} |
||||
System.out.println(); |
||||
for (int j = 0; j < to.length() + 1; j++) { |
||||
System.out.print((j > 0 ? to.charAt(j - 1) : " ") + " "); |
||||
for (int i = 0; i < from.length() + 1; i++) { |
||||
System.out.print(d[i][j]); |
||||
if (i == from.length() && j == to.length()) |
||||
System.out.print("<"); |
||||
else if (i == from.length() - 1 && j == to.length()) |
||||
System.out.print(">"); |
||||
else |
||||
System.out.print(" "); |
||||
} |
||||
System.out.println(); |
||||
} |
||||
} |
||||
return d[from.length()][to.length()]; |
||||
} |
||||
|
||||
private int min(int i, int j, int k) { |
||||
int min = i; |
||||
if (j < min) |
||||
min = j; |
||||
if (k < min) |
||||
min = k; |
||||
return min; |
||||
} |
||||
|
||||
} |
||||
@ -1,73 +0,0 @@
@@ -1,73 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2008 the original author or authors. |
||||
* |
||||
* 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 org.springframework.expression.spel.ast; |
||||
|
||||
import java.util.regex.Matcher; |
||||
import java.util.regex.Pattern; |
||||
import java.util.regex.PatternSyntaxException; |
||||
|
||||
import org.antlr.runtime.Token; |
||||
import org.springframework.expression.EvaluationException; |
||||
import org.springframework.expression.spel.ExpressionState; |
||||
import org.springframework.expression.spel.SpelException; |
||||
import org.springframework.expression.spel.SpelMessages; |
||||
|
||||
/** |
||||
* Implements the like operator. The like operator behaves the same as the SQL LIKE operator. The first operand is |
||||
* compared against the expression supplied as the second operand. This expression supports two wildcards: % meaning any |
||||
* string of any length, and _ meaning any single character. |
||||
* |
||||
* @author Andy Clement |
||||
*/ |
||||
public class OperatorLike extends Operator { |
||||
|
||||
public OperatorLike(Token payload) { |
||||
super(payload); |
||||
} |
||||
|
||||
@Override |
||||
public String getOperatorName() { |
||||
return "like"; |
||||
} |
||||
|
||||
@Override |
||||
public Boolean getValue(ExpressionState state) throws EvaluationException { |
||||
SpelNode leftOp = getLeftOperand(); |
||||
SpelNode rightOp = getRightOperand(); |
||||
Object left = leftOp.getValue(state, String.class); |
||||
Object right = getRightOperand().getValue(state); |
||||
try { |
||||
if (!(left instanceof String)) { |
||||
throw new SpelException(leftOp.getCharPositionInLine(), |
||||
SpelMessages.INVALID_FIRST_OPERAND_FOR_LIKE_OPERATOR, left); |
||||
} |
||||
if (!(right instanceof String)) { |
||||
throw new SpelException(rightOp.getCharPositionInLine(), |
||||
SpelMessages.INVALID_SECOND_OPERAND_FOR_LIKE_OPERATOR, right); |
||||
} |
||||
// Translate that pattern to a java regex
|
||||
// not really the best option, what if the right operand already had regex related chars in it?
|
||||
String likePattern = (String) right; |
||||
likePattern = likePattern.replace('_', '.'); |
||||
likePattern = likePattern.replaceAll("%", ".*"); |
||||
Pattern pattern = Pattern.compile(likePattern); |
||||
Matcher matcher = pattern.matcher((String) left); |
||||
return matcher.matches(); |
||||
} catch (PatternSyntaxException pse) { |
||||
throw new SpelException(rightOp.getCharPositionInLine(), pse, SpelMessages.INVALID_PATTERN, right); |
||||
} |
||||
} |
||||
} |
||||
@ -1,113 +0,0 @@
@@ -1,113 +0,0 @@
|
||||
/* |
||||
* Copyright 2004-2008 the original author or authors. |
||||
* |
||||
* 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 org.springframework.expression.spel.ast; |
||||
|
||||
import org.antlr.runtime.Token; |
||||
import org.springframework.expression.EvaluationException; |
||||
import org.springframework.expression.spel.ExpressionState; |
||||
import org.springframework.expression.spel.SpelException; |
||||
import org.springframework.expression.spel.SpelMessages; |
||||
|
||||
public class OperatorSoundsLike extends Operator { |
||||
|
||||
public OperatorSoundsLike(Token payload) { |
||||
super(payload); |
||||
} |
||||
|
||||
@Override |
||||
public Object getValue(ExpressionState state) throws EvaluationException { |
||||
Object left = getLeftOperand().getValue(state); |
||||
Object right = getRightOperand().getValue(state); |
||||
if (!(left instanceof String)) { |
||||
throw new SpelException(getCharPositionInLine(), SpelMessages.SOUNDSLIKE_NEEDS_STRING_OPERAND, left |
||||
.getClass().getName()); |
||||
} |
||||
if (!(right instanceof String)) { |
||||
throw new SpelException(getCharPositionInLine(), SpelMessages.SOUNDSLIKE_NEEDS_STRING_OPERAND, right |
||||
.getClass().getName()); |
||||
} |
||||
String leftSoundex = computeSoundex((String) left); |
||||
String rightSoundex = computeSoundex((String) right); |
||||
return state.getTypeComparator().compare(leftSoundex, rightSoundex) == 0; |
||||
} |
||||
|
||||
// TODO if we keep soundslike, improve upon this basic implementation
|
||||
private String computeSoundex(String input) { |
||||
if (input == null || input.length() == 0) |
||||
return "0000"; |
||||
input = input.toUpperCase(); |
||||
StringBuilder soundex = new StringBuilder(); |
||||
soundex.append(input.charAt(0)); |
||||
for (int i = 1; i < input.length(); i++) { |
||||
char ch = input.charAt(i); |
||||
if ("HW".indexOf(ch) != -1) |
||||
continue; // remove HWs now
|
||||
if ("BFPV".indexOf(ch) != -1) { |
||||
soundex.append("1"); |
||||
} else if ("CGJKQSXZ".indexOf(ch) != -1) { |
||||
soundex.append("2"); |
||||
} else if ("DT".indexOf(ch) != -1) { |
||||
soundex.append("3"); |
||||
} else if ("L".indexOf(ch) != -1) { |
||||
soundex.append("4"); |
||||
} else if ("MN".indexOf(ch) != -1) { |
||||
soundex.append("5"); |
||||
} else if ("R".indexOf(ch) != -1) { |
||||
soundex.append("6"); |
||||
|
||||
} else { |
||||
soundex.append(ch); |
||||
} |
||||
} |
||||
StringBuilder shorterSoundex = new StringBuilder(); |
||||
shorterSoundex.append(soundex.charAt(0)); |
||||
for (int i = 1; i < soundex.length(); i++) { |
||||
if ((i + 1) < soundex.length() && soundex.charAt(i) == soundex.charAt(i + 1)) |
||||
continue; |
||||
if ("AEIOUY".indexOf(soundex.charAt(i)) != -1) |
||||
continue; |
||||
shorterSoundex.append(soundex.charAt(i)); |
||||
} |
||||
shorterSoundex.append("0000"); |
||||
return shorterSoundex.substring(0, 4); |
||||
} |
||||
|
||||
// wikipedia:
|
||||
// The Soundex code for a name consists of a letter followed by three numbers: the letter is the first letter of the
|
||||
// name, and the numbers encode the remaining consonants. Similar sounding consonants share the same number so, for
|
||||
// example, the labial B, F, P and V are all encoded as 1. Vowels can affect the coding, but are never coded
|
||||
// directly unless they appear at the start of the name.
|
||||
// The exact algorithm is as follows:
|
||||
// Retain the first letter of the string
|
||||
// Remove all occurrences of the following letters, unless it is the first letter: a, e, h, i, o, u, w, y
|
||||
// Assign numbers to the remaining letters (after the first) as follows:
|
||||
// b, f, p, v = 1
|
||||
// c, g, j, k, q, s, x, z = 2
|
||||
// d, t = 3
|
||||
// l = 4
|
||||
// m, n = 5
|
||||
// r = 6
|
||||
// If two or more letters with the same number were adjacent in the original name (before step 1), or adjacent
|
||||
// except for any intervening h and w (American census only), then omit all but the first.
|
||||
// Return the first four characters, right-padding with zeroes if there are fewer than four.
|
||||
// Using this algorithm, both "Robert" and "Rupert" return the same string "R163" while "Rubin" yields "R150".
|
||||
|
||||
@Override |
||||
public String getOperatorName() { |
||||
return "soundslike"; |
||||
} |
||||
|
||||
} |
||||
@ -1,92 +1,89 @@
@@ -1,92 +1,89 @@
|
||||
COMMA=51 |
||||
GREATER_THAN_OR_EQUAL=79 |
||||
EXPRESSIONLIST=4 |
||||
SELECT_FIRST=58 |
||||
COMMA=51 |
||||
HOLDER=14 |
||||
GREATER_THAN=78 |
||||
TYPE=60 |
||||
EXPRESSIONLIST=4 |
||||
MINUS=41 |
||||
MAP_ENTRY=25 |
||||
SELECT_LAST=59 |
||||
NUMBER=29 |
||||
ARGLIST=11 |
||||
BANG=46 |
||||
LESS_THAN=76 |
||||
METHOD=26 |
||||
BANG=46 |
||||
ARGLIST=11 |
||||
FALSE=70 |
||||
METHOD=26 |
||||
PROPERTY_OR_FIELD=9 |
||||
LBRACKET=53 |
||||
MOD=44 |
||||
INDEXER=10 |
||||
CONSTRUCTOR_ARRAY=15 |
||||
FUNCTIONREF=17 |
||||
NULL_LITERAL=66 |
||||
NAMED_ARGUMENT=16 |
||||
OR=38 |
||||
PIPE=62 |
||||
DOT=47 |
||||
AND=39 |
||||
RCURLY=56 |
||||
EXPRESSION=6 |
||||
AND=39 |
||||
LCURLY=63 |
||||
DATE_LITERAL=13 |
||||
REAL_TYPE_SUFFIX=92 |
||||
QUALIFIED_IDENTIFIER=7 |
||||
SELECT=57 |
||||
REAL_TYPE_SUFFIX=89 |
||||
STRING_LITERAL=64 |
||||
SUBTRACT=28 |
||||
SELECT=57 |
||||
QUALIFIED_IDENTIFIER=7 |
||||
RBRACKET=54 |
||||
RPAREN=33 |
||||
BETWEEN=82 |
||||
SIGN=93 |
||||
PLUS=40 |
||||
INTEGER_LITERAL=5 |
||||
AT=52 |
||||
RANGE=19 |
||||
SOUNDSLIKE=85 |
||||
WS=89 |
||||
DOLLAR=50 |
||||
LESS_THAN_OR_EQUAL=77 |
||||
HEXADECIMAL_INTEGER_LITERAL=67 |
||||
LAMBDA=61 |
||||
SEMI=31 |
||||
EQUAL=74 |
||||
DOT_ESCAPED=88 |
||||
QMARK=36 |
||||
COLON=37 |
||||
PROJECT=55 |
||||
DIV=43 |
||||
REAL_LITERAL=68 |
||||
ADD=27 |
||||
TRUE=69 |
||||
EXPONENT_PART=91 |
||||
POUND=48 |
||||
HOLDER=14 |
||||
SELECT_FIRST=58 |
||||
TYPE=60 |
||||
MAP_ENTRY=25 |
||||
SELECT_LAST=59 |
||||
LBRACKET=53 |
||||
MOD=44 |
||||
FUNCTIONREF=17 |
||||
OR=38 |
||||
RCURLY=56 |
||||
SUBTRACT=28 |
||||
ASSIGN=34 |
||||
BETWEEN=82 |
||||
RPAREN=33 |
||||
SIGN=90 |
||||
LPAREN=30 |
||||
HEX_DIGIT=73 |
||||
PLUS=40 |
||||
LIST_INITIALIZER=21 |
||||
APOS=87 |
||||
APOS=84 |
||||
INTEGER_LITERAL=5 |
||||
AT=52 |
||||
ID=49 |
||||
NOT_EQUAL=75 |
||||
RANGE=19 |
||||
POWER=45 |
||||
TYPEREF=18 |
||||
DISTANCETO=86 |
||||
DECIMAL_DIGIT=71 |
||||
WS=86 |
||||
IS=81 |
||||
DOLLAR=50 |
||||
LESS_THAN_OR_EQUAL=77 |
||||
SEMIRPAREN=32 |
||||
DQ_STRING_LITERAL=65 |
||||
LIKE=83 |
||||
HEXADECIMAL_INTEGER_LITERAL=67 |
||||
MAP_INITIALIZER=22 |
||||
LAMBDA=61 |
||||
LOCALFUNC=24 |
||||
IN=80 |
||||
CONSTRUCTOR=12 |
||||
SEMI=31 |
||||
INTEGER_TYPE_SUFFIX=72 |
||||
MATCHES=84 |
||||
UPTO=90 |
||||
EQUAL=74 |
||||
MATCHES=83 |
||||
DOT_ESCAPED=85 |
||||
UPTO=87 |
||||
QMARK=36 |
||||
REFERENCE=8 |
||||
PROJECT=55 |
||||
DEFAULT=35 |
||||
COLON=37 |
||||
DIV=43 |
||||
LOCALVAR=23 |
||||
STAR=42 |
||||
REAL_LITERAL=68 |
||||
VARIABLEREF=20 |
||||
'date'=95 |
||||
'new'=94 |
||||
EXPONENT_PART=88 |
||||
TRUE=69 |
||||
ADD=27 |
||||
POUND=48 |
||||
'date'=92 |
||||
'new'=91 |
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue