]> source.dussan.org Git - jackcess.git/commitdiff
implement IsNumeric; add support for hex/oct integer strings
authorJames Ahlborn <jtahlborn@yahoo.com>
Tue, 18 Sep 2018 02:55:40 +0000 (02:55 +0000)
committerJames Ahlborn <jtahlborn@yahoo.com>
Tue, 18 Sep 2018 02:55:40 +0000 (02:55 +0000)
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@1199 f203690c-595d-4dc9-a70b-905162fa7fd2

src/main/java/com/healthmarketscience/jackcess/expr/package-info.java
src/main/java/com/healthmarketscience/jackcess/impl/expr/DefaultFunctions.java
src/main/java/com/healthmarketscience/jackcess/impl/expr/StringValue.java
src/test/java/com/healthmarketscience/jackcess/impl/expr/DefaultFunctionsTest.java
src/test/java/com/healthmarketscience/jackcess/impl/expr/ExpressionatorTest.java

index 6531eeabd0247a0a346c48926c32672b9eff8476..416c96eae5193b632f13f32c9444ecfe2d635452 100644 (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>
index e927f9a6c6bd5b8092175ab610c69f7c57c69648..20de8ca3b6edea052930b1d3aadc1c8f7cfb6220 100644 (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) {
index d3e2cacc83ccc77b68ed0d25fcabaa012a055776..51b9c6a3899c3725222d50a58f4c9e9d14120729 100644 (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;
+  }
 }
index ca1a67c8e9a57043c7d0db2328f7ef51cba93aeb..e8aa234fc9d7a96605f7d24d34a0886785d9477b 100644 (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')"));
index 188172d6a4f0d43d0fbc2c2b30ee4fe633f42923..5b623a0e9840aad6ad11739403cf7c0e42b43884 100644 (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);