Skip to content

Commit

Permalink
Fixed the evaluation of 'substring' built-in function
Browse files Browse the repository at this point in the history
According to the XQuery specification, this function must graciously
handle out-of-range 'startPos' and 'length' argument values.

See http://www.w3.org/TR/xquery-operators/#func-substring
  • Loading branch information
vruusmann committed Oct 27, 2015
1 parent 7a1fe2c commit b4c8cdf
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -404,13 +404,18 @@ public FieldValue evaluate(List<FieldValue> arguments){
throw new FunctionException(this, "Invalid position value " + position + ". Must be equal or greater than 1");
}

// "The first character of a string is located at position 1 (not position 0)"
int javaPosition = Math.min(position - 1, string.length());

int length = (arguments.get(2)).asInteger();
if(length < 0){
throw new FunctionException(this, "Invalid length value " + length);
}

// "The first character of a string is located at position 1 (not position 0)"
String result = string.substring(position - 1, (position + length) - 1);
int javaLength = Math.min(length, (string.length() - javaPosition));

// This expression must never throw a StringIndexOutOfBoundsException
String result = string.substring(javaPosition, javaPosition + javaLength);

return FieldValueUtil.create(result);
}
Expand Down
14 changes: 12 additions & 2 deletions pmml-evaluator/src/test/java/org/jpmml/evaluator/FunctionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -217,11 +217,21 @@ public void evaluateStringFunctions(){
assertEquals("VALUE", evaluate(Functions.UPPERCASE, "Value"));
assertEquals("value", evaluate(Functions.LOWERCASE, "Value"));

assertEquals("Bc9", evaluate(Functions.SUBSTRING, "aBc9x", 2, 3));

assertEquals("", evaluate(Functions.SUBSTRING, "", 1, 0));
assertEquals("", evaluate(Functions.SUBSTRING, "", 1, Integer.MAX_VALUE));
assertEquals("", evaluate(Functions.SUBSTRING, "", Integer.MAX_VALUE, 0));
assertEquals("", evaluate(Functions.SUBSTRING, "", Integer.MAX_VALUE, Integer.MAX_VALUE));

assertEquals("", evaluate(Functions.SUBSTRING, "value", 1, 0));
assertEquals("valu", evaluate(Functions.SUBSTRING, "value", 1, 4));
assertEquals("value", evaluate(Functions.SUBSTRING, "value", 1, 5));

assertEquals("value", evaluate(Functions.SUBSTRING, "value", 1, Integer.MAX_VALUE));
assertEquals("alue", evaluate(Functions.SUBSTRING, "value", 2, 4));
assertEquals("valu", evaluate(Functions.SUBSTRING, "value", 1, 4));
assertEquals("alue", evaluate(Functions.SUBSTRING, "value", 2, Integer.MAX_VALUE));
assertEquals("", evaluate(Functions.SUBSTRING, "value", 6, Integer.MAX_VALUE));
assertEquals("", evaluate(Functions.SUBSTRING, "value", Integer.MAX_VALUE, Integer.MAX_VALUE));

assertEquals("value", evaluate(Functions.TRIM_BLANKS, "\tvalue\t"));
}
Expand Down

0 comments on commit b4c8cdf

Please sign in to comment.