]> source.dussan.org Git - poi.git/commitdiff
fixed OperandResolver to correctly handle inputs with leading decimal place, see...
authorYegor Kozlov <yegor@apache.org>
Tue, 10 Aug 2010 18:49:21 +0000 (18:49 +0000)
committerYegor Kozlov <yegor@apache.org>
Tue, 10 Aug 2010 18:49:21 +0000 (18:49 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@984161 13f79535-47bb-0310-9956-ffa450edef68

src/documentation/content/xdocs/status.xml
src/java/org/apache/poi/hssf/record/formula/eval/OperandResolver.java
src/testcases/org/apache/poi/hssf/record/formula/eval/TestOperandResolver.java [new file with mode: 0644]

index 7f44b2b410fcc1989e877fdf42afd1be305036fb..56de7a0910984ed3b644c431efa7f7be705f77de 100644 (file)
@@ -34,6 +34,8 @@
 
     <changes>
         <release version="3.7-beta3" date="2010-??-??">
+           <action dev="POI-DEVELOPERS" type="fix">49725 - avoid exception in OperandResolver.parseDouble when input is minus ("-")</action>
+           <action dev="POI-DEVELOPERS" type="fix">49723 - fixed OperandResolver to correctly handle inputs with leading decimal place</action>
            <action dev="POI-DEVELOPERS" type="add">initial support for Excel autofilter</action>
         </release>
         <release version="3.7-beta2" date="2010-08-09">
index 0b9116db3ea8886bf2eb20a8d63492eba800c549..75d68540fe4f5b336db3e48316b0309802c7c8ee 100644 (file)
 
 package org.apache.poi.hssf.record.formula.eval;
 
+import java.util.regex.Pattern;
+
 /**
  * Provides functionality for evaluating arguments to functions and operators.
  *
  * @author Josh Micich
+ * @author Brendan Nolan
  */
 public final class OperandResolver {
 
+       // Based on regular expression defined in JavaDoc at {@link java.lang.Double#valueOf}
+       // modified to remove support for NaN, Infinity, Hexadecimal support and floating type suffixes
+    private static final String Digits = "(\\p{Digit}+)";
+    private static final String Exp    = "[eE][+-]?"+Digits;
+    private static final String fpRegex        =
+                   ("[\\x00-\\x20]*" + 
+                    "[+-]?(" + 
+                    "((("+Digits+"(\\.)?("+Digits+"?)("+Exp+")?)|"+        
+                    "(\\.("+Digits+")("+Exp+")?))))"+       
+                    "[\\x00-\\x20]*"); 
+           
+       
        private OperandResolver() {
                // no instances of this class
        }
@@ -214,11 +229,15 @@ public final class OperandResolver {
 
        /**
         * Converts a string to a double using standard rules that Excel would use.<br/>
-        * Tolerates currency prefixes, commas, leading and trailing spaces.<p/>
+        * Tolerates leading and trailing spaces, <p/>
+        * 
+        * Doesn't support currency prefixes, commas, percentage signs or arithmetic operations strings.  
         *
         *  Some examples:<br/>
         *  " 123 " -&gt; 123.0<br/>
         *  ".123" -&gt; 0.123<br/>
+        *  "1E4" -&gt; 1000<br/>
+        *  "-123" -&gt; -123.0<br/>
         *  These not supported yet:<br/>
         *  " $ 1,000.00 " -&gt; 1000.0<br/>
         *  "$1.25E4" -&gt; 12500.0<br/>
@@ -228,29 +247,17 @@ public final class OperandResolver {
         * @return <code>null</code> if the specified text cannot be parsed as a number
         */
        public static Double parseDouble(String pText) {
-               String text = pText.trim();
-               if(text.length() < 1) {
-                       return null;
-               }
-               boolean isPositive = true;
-               if(text.charAt(0) == '-') {
-                       isPositive = false;
-                       text= text.substring(1).trim();
-               }
-
-               if(!Character.isDigit(text.charAt(0))) {
-                       // avoid using NumberFormatException to tell when string is not a number
-                       return null;
-               }
-               // TODO - support notation like '1E3' (==1000)
-
-               double val;
-               try {
-                       val = Double.parseDouble(text);
-               } catch (NumberFormatException e) {
-                       return null;
-               }
-               return new Double(isPositive ? +val : -val);
+               
+           if (Pattern.matches(fpRegex, pText))
+                       try {
+                               return Double.parseDouble(pText);
+                       } catch (NumberFormatException e) {
+                               return null;
+                       }
+           else {
+               return null;
+           }
+               
        }
 
        /**
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestOperandResolver.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestOperandResolver.java
new file mode 100644 (file)
index 0000000..98ddade
--- /dev/null
@@ -0,0 +1,89 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You 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.apache.poi.hssf.record.formula.eval;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+
+/**
+ * Tests for <tt>OperandResolver</tt>
+ *
+ * @author Brendan Nolan
+ */
+public final class TestOperandResolver extends TestCase {
+
+       public void testParseDouble_bug48472() {
+               
+               String value = "-";
+               
+               Double resolvedValue = null;
+               
+               try {
+                       resolvedValue = OperandResolver.parseDouble(value);
+               } catch (StringIndexOutOfBoundsException e) { 
+                       throw new AssertionFailedError("Identified bug 48472");
+               }
+               
+               assertEquals(null, resolvedValue);
+               
+       }
+       
+       public void testParseDouble_bug49723() {
+               
+               String value = ".1";
+               
+               Double resolvedValue = null;
+               
+               resolvedValue = OperandResolver.parseDouble(value);
+               
+               assertNotNull("Identified bug 49723", resolvedValue);
+               
+       }
+       
+       /**
+        * 
+        * Tests that a list of valid strings all return a non null value from {@link OperandResolver#parseDouble(String)}
+        * 
+        */
+       public void testParseDoubleValidStrings() {
+                               
+               String[] values = new String[]{".19", "0.19", "1.9", "1E4", "-.19", "-0.19", "8.5","-1E4", ".5E6","+1.5","+1E5", "  +1E5  "};
+               
+               for (String value : values) {
+                       assertTrue(OperandResolver.parseDouble(value) != null);
+                       assertEquals(OperandResolver.parseDouble(value), Double.parseDouble(value));
+               }
+
+       }
+       
+       /**
+        * 
+        * Tests that a list of invalid strings all return null from {@link OperandResolver#parseDouble(String)}
+        * 
+        */
+       public void testParseDoubleInvalidStrings() {
+               
+               String[] values = new String[]{"-", "ABC", "-X", "1E5a", "Infinity", "NaN", ".5F", "1,000"};
+               
+               for (String value : values) {
+                       assertEquals(null, OperandResolver.parseDouble(value));
+               }
+
+       }
+       
+}