Browse Source

implement IsNumeric; add support for hex/oct integer strings

git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@1199 f203690c-595d-4dc9-a70b-905162fa7fd2
tags/jackcess-2.2.1
James Ahlborn 5 years ago
parent
commit
010cc904a5

+ 2
- 2
src/main/java/com/healthmarketscience/jackcess/expr/package-info.java View File

@@ -178,7 +178,7 @@ limitations under the License.
* <tr class="TableRowColor"><td>IsError</td><td></td></tr>
* <tr class="TableRowColor"><td>IsMissing</td><td></td></tr>
* <tr class="TableRowColor"><td>IsNull</td><td>Y</td></tr>
* <tr class="TableRowColor"><td>IsNumeric</td><td></td></tr>
* <tr class="TableRowColor"><td>IsNumeric</td><td>Y</td></tr>
* <tr class="TableRowColor"><td>IsObject</td><td></td></tr>
* <tr class="TableRowColor"><td>TypeName</td><td>Y</td></tr>
* <tr class="TableRowColor"><td>VarType</td><td>Y</td></tr>
@@ -216,7 +216,7 @@ limitations under the License.
*
* <table border="1" width="25%" cellpadding="3" cellspacing="0">
* <tr class="TableHeadingColor" align="left"><th>Function</th><th>Supported</th></tr>
* <tr class="TableRowColor"><td>Format</td><td></td></tr>
* <tr class="TableRowColor"><td>Format[$]</td><td></td></tr>
* <tr class="TableRowColor"><td>InStr</td><td>Y</td></tr>
* <tr class="TableRowColor"><td>InStrRev</td><td>Y</td></tr>
* <tr class="TableRowColor"><td>LCase[$]</td><td>Y</td></tr>

+ 20
- 0
src/main/java/com/healthmarketscience/jackcess/impl/expr/DefaultFunctions.java View File

@@ -246,6 +246,26 @@ public class DefaultFunctions
}
});

public static final Function ISNUMERIC = registerFunc(new Func1("IsNumeric") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {
if(param1.getType().isNumeric()) {
return ValueSupport.TRUE_VAL;
}

if(param1.getType() == Value.Type.STRING) {
try {
param1.getAsBigDecimal();
return ValueSupport.TRUE_VAL;
} catch(NumberFormatException ignored) {
// fall through to FALSE_VAL
}
}

return ValueSupport.FALSE_VAL;
}
});

public static final Function VARTYPE = registerFunc(new Func1("VarType") {
@Override
protected Value eval1(EvalContext ctx, Value param1) {

+ 35
- 4
src/main/java/com/healthmarketscience/jackcess/impl/expr/StringValue.java View File

@@ -17,6 +17,8 @@ limitations under the License.
package com.healthmarketscience.jackcess.impl.expr;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.regex.Pattern;

/**
*
@@ -26,6 +28,12 @@ public class StringValue extends BaseValue
{
private static final Object NOT_A_NUMBER = new Object();

private static final char NUMBER_BASE_PREFIX = '&';
private static final Pattern OCTAL_PAT =
Pattern.compile(NUMBER_BASE_PREFIX + "[oO][0-7]+");
private static final Pattern HEX_PAT =
Pattern.compile(NUMBER_BASE_PREFIX + "[hH]\\p{XDigit}+");

private final String _val;
private Object _num;

@@ -75,13 +83,36 @@ public class StringValue extends BaseValue
if(_num == null) {
// see if it is parseable as a number
try {
_num = ValueSupport.normalize(new BigDecimal(_val));
return (BigDecimal)_num;
// ignore extraneous whitespace whitespace and handle "&[hH]" or
// "&[oO]" prefix (only supports integers)
String tmpVal = _val.trim();
if(tmpVal.length() > 0) {

if(tmpVal.charAt(0) != NUMBER_BASE_PREFIX) {
// parse using standard numeric support
_num = ValueSupport.normalize(new BigDecimal(tmpVal));
return (BigDecimal)_num;
}

// parse as hex/octal symbolic value
if(HEX_PAT.matcher(tmpVal).matches()) {
return parseIntegerString(tmpVal, 16);
} else if(OCTAL_PAT.matcher(tmpVal).matches()) {
return parseIntegerString(tmpVal, 8);
}

// fall through to NaN
}
} catch(NumberFormatException nfe) {
_num = NOT_A_NUMBER;
// fall through to throw...
// fall through to NaN...
}
_num = NOT_A_NUMBER;
}
throw new NumberFormatException("Invalid number '" + _val + "'");
}

private BigDecimal parseIntegerString(String tmpVal, int radix) {
_num = new BigDecimal(new BigInteger(tmpVal.substring(2), radix));
return (BigDecimal)_num;
}
}

+ 14
- 0
src/test/java/com/healthmarketscience/jackcess/impl/expr/DefaultFunctionsTest.java View File

@@ -80,7 +80,21 @@ public class DefaultFunctionsTest extends TestCase
assertEquals("-42", eval("=CStr(-42)"));

assertEquals(-1, eval("=IsNull(Null)"));
assertEquals(0, eval("=IsNull(13)"));
assertEquals(-1, eval("=IsDate(#01/02/2003#)"));
assertEquals(0, eval("=IsDate('foo')"));

assertEquals(0, eval("=IsNumeric(Null)"));
assertEquals(0, eval("=IsNumeric('foo')"));
assertEquals(0, eval("=IsNumeric(#01/02/2003#)"));
assertEquals(-1, eval("=IsNumeric(37)"));
assertEquals(-1, eval("=IsNumeric(' 37 ')"));
assertEquals(-1, eval("=IsNumeric(' -37.5e2 ')"));
assertEquals(-1, eval("=IsNumeric(' &H37 ')"));
assertEquals(0, eval("=IsNumeric(' &H37foo ')"));
assertEquals(0, eval("=IsNumeric(' &o39 ')"));
assertEquals(-1, eval("=IsNumeric(' &o36 ')"));
assertEquals(0, eval("=IsNumeric(' &o36.1 ')"));

assertEquals(1, eval("=VarType(Null)"));
assertEquals(8, eval("=VarType('blah')"));

+ 4
- 0
src/test/java/com/healthmarketscience/jackcess/impl/expr/ExpressionatorTest.java View File

@@ -383,6 +383,10 @@ public class ExpressionatorTest extends TestCase

assertEquals(37d, eval("=\"25\" + 12"));
assertEquals(37d, eval("=12 + \"25\""));
assertEquals(37d, eval("=\" 25 \" + 12"));
assertEquals(37d, eval("=\" &h1A \" + 11"));
assertEquals(37d, eval("=\" &h1a \" + 11"));
assertEquals(37d, eval("=\" &O32 \" + 11"));

evalFail(("=12 - \"foo\""), RuntimeException.class);
evalFail(("=\"foo\" - 12"), RuntimeException.class);

Loading…
Cancel
Save