mirror of https://github.com/apache/poi.git
fixed OperandResolver to correctly handle inputs with leading decimal place, see Bug #49723
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@984161 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
14b5b74989
commit
125c86b6de
|
@ -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">
|
||||
|
|
|
@ -17,13 +17,28 @@
|
|||
|
||||
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 " -> 123.0<br/>
|
||||
* ".123" -> 0.123<br/>
|
||||
* "1E4" -> 1000<br/>
|
||||
* "-123" -> -123.0<br/>
|
||||
* These not supported yet:<br/>
|
||||
* " $ 1,000.00 " -> 1000.0<br/>
|
||||
* "$1.25E4" -> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue