13 changed files with 9531 additions and 11117 deletions
@ -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 @@ |
|||||||
/* |
|
||||||
* 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 @@ |
|||||||
/* |
|
||||||
* 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 @@ |
|||||||
COMMA=51 |
|
||||||
GREATER_THAN_OR_EQUAL=79 |
GREATER_THAN_OR_EQUAL=79 |
||||||
EXPRESSIONLIST=4 |
SELECT_FIRST=58 |
||||||
|
COMMA=51 |
||||||
|
HOLDER=14 |
||||||
GREATER_THAN=78 |
GREATER_THAN=78 |
||||||
|
TYPE=60 |
||||||
|
EXPRESSIONLIST=4 |
||||||
MINUS=41 |
MINUS=41 |
||||||
|
MAP_ENTRY=25 |
||||||
|
SELECT_LAST=59 |
||||||
NUMBER=29 |
NUMBER=29 |
||||||
ARGLIST=11 |
|
||||||
BANG=46 |
|
||||||
LESS_THAN=76 |
LESS_THAN=76 |
||||||
METHOD=26 |
BANG=46 |
||||||
|
ARGLIST=11 |
||||||
FALSE=70 |
FALSE=70 |
||||||
|
METHOD=26 |
||||||
PROPERTY_OR_FIELD=9 |
PROPERTY_OR_FIELD=9 |
||||||
|
LBRACKET=53 |
||||||
|
MOD=44 |
||||||
INDEXER=10 |
INDEXER=10 |
||||||
CONSTRUCTOR_ARRAY=15 |
CONSTRUCTOR_ARRAY=15 |
||||||
|
FUNCTIONREF=17 |
||||||
NULL_LITERAL=66 |
NULL_LITERAL=66 |
||||||
NAMED_ARGUMENT=16 |
NAMED_ARGUMENT=16 |
||||||
|
OR=38 |
||||||
PIPE=62 |
PIPE=62 |
||||||
DOT=47 |
DOT=47 |
||||||
AND=39 |
RCURLY=56 |
||||||
EXPRESSION=6 |
EXPRESSION=6 |
||||||
|
AND=39 |
||||||
LCURLY=63 |
LCURLY=63 |
||||||
DATE_LITERAL=13 |
DATE_LITERAL=13 |
||||||
REAL_TYPE_SUFFIX=92 |
REAL_TYPE_SUFFIX=89 |
||||||
QUALIFIED_IDENTIFIER=7 |
|
||||||
SELECT=57 |
|
||||||
STRING_LITERAL=64 |
STRING_LITERAL=64 |
||||||
SUBTRACT=28 |
SELECT=57 |
||||||
|
QUALIFIED_IDENTIFIER=7 |
||||||
RBRACKET=54 |
RBRACKET=54 |
||||||
RPAREN=33 |
SUBTRACT=28 |
||||||
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 |
|
||||||
ASSIGN=34 |
ASSIGN=34 |
||||||
|
BETWEEN=82 |
||||||
|
RPAREN=33 |
||||||
|
SIGN=90 |
||||||
LPAREN=30 |
LPAREN=30 |
||||||
HEX_DIGIT=73 |
HEX_DIGIT=73 |
||||||
|
PLUS=40 |
||||||
LIST_INITIALIZER=21 |
LIST_INITIALIZER=21 |
||||||
APOS=87 |
APOS=84 |
||||||
|
INTEGER_LITERAL=5 |
||||||
|
AT=52 |
||||||
ID=49 |
ID=49 |
||||||
NOT_EQUAL=75 |
NOT_EQUAL=75 |
||||||
|
RANGE=19 |
||||||
POWER=45 |
POWER=45 |
||||||
TYPEREF=18 |
TYPEREF=18 |
||||||
DISTANCETO=86 |
|
||||||
DECIMAL_DIGIT=71 |
DECIMAL_DIGIT=71 |
||||||
|
WS=86 |
||||||
IS=81 |
IS=81 |
||||||
|
DOLLAR=50 |
||||||
|
LESS_THAN_OR_EQUAL=77 |
||||||
SEMIRPAREN=32 |
SEMIRPAREN=32 |
||||||
DQ_STRING_LITERAL=65 |
DQ_STRING_LITERAL=65 |
||||||
LIKE=83 |
HEXADECIMAL_INTEGER_LITERAL=67 |
||||||
MAP_INITIALIZER=22 |
MAP_INITIALIZER=22 |
||||||
|
LAMBDA=61 |
||||||
LOCALFUNC=24 |
LOCALFUNC=24 |
||||||
IN=80 |
IN=80 |
||||||
CONSTRUCTOR=12 |
CONSTRUCTOR=12 |
||||||
|
SEMI=31 |
||||||
INTEGER_TYPE_SUFFIX=72 |
INTEGER_TYPE_SUFFIX=72 |
||||||
MATCHES=84 |
EQUAL=74 |
||||||
UPTO=90 |
MATCHES=83 |
||||||
|
DOT_ESCAPED=85 |
||||||
|
UPTO=87 |
||||||
|
QMARK=36 |
||||||
REFERENCE=8 |
REFERENCE=8 |
||||||
|
PROJECT=55 |
||||||
DEFAULT=35 |
DEFAULT=35 |
||||||
|
COLON=37 |
||||||
|
DIV=43 |
||||||
LOCALVAR=23 |
LOCALVAR=23 |
||||||
STAR=42 |
STAR=42 |
||||||
|
REAL_LITERAL=68 |
||||||
VARIABLEREF=20 |
VARIABLEREF=20 |
||||||
'date'=95 |
EXPONENT_PART=88 |
||||||
'new'=94 |
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