diff --git a/src/main/java/org/apache/commons/lang3/math/NumberUtils.java b/src/main/java/org/apache/commons/lang3/math/NumberUtils.java index d4863e746be..7327fac06b3 100644 --- a/src/main/java/org/apache/commons/lang3/math/NumberUtils.java +++ b/src/main/java/org/apache/commons/lang3/math/NumberUtils.java @@ -23,7 +23,6 @@ import java.util.Objects; import java.util.function.Consumer; -import org.apache.commons.lang3.CharUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; @@ -109,7 +108,7 @@ private static boolean accept(final Consumer consumer, final T obj) { try { consumer.accept(obj); return true; - } catch (Exception e) { + } catch (final Exception e) { return false; } } @@ -584,106 +583,12 @@ public static boolean isCreatable(final String str) { if (StringUtils.isEmpty(str)) { return false; } - final char[] chars = str.toCharArray(); - int sz = chars.length; - boolean hasExp = false; - boolean hasDecPoint = false; - boolean allowSigns = false; - boolean foundDigit = false; - // deal with any possible sign up front - final int start = isSign(chars[0]) ? 1 : 0; - if (sz > start + 1 && chars[start] == '0' && !StringUtils.contains(str, '.')) { // leading 0, skip if is a decimal number - if (chars[start + 1] == 'x' || chars[start + 1] == 'X') { // leading 0x/0X - int i = start + 2; - if (i == sz) { - return false; // str == "0x" - } - // checking hex (it can't be anything else) - for (; i < chars.length; i++) { - if (!CharUtils.isHex(chars[i])) { - return false; - } - } - return true; - } - if (Character.isDigit(chars[start + 1])) { - // leading 0, but not hex, must be octal - int i = start + 1; - for (; i < chars.length; i++) { - if (!CharUtils.isOctal(chars[i])) { - return false; - } - } - return true; - } - } - sz--; // don't want to loop to the last char, check it afterwards - // for type qualifiers - int i = start; - // loop to the next to last char or to the last char if we need another digit to - // make a valid number (e.g. chars[0..5] = "1234E") - while (i < sz || i < sz + 1 && allowSigns && !foundDigit) { - if (CharUtils.isAsciiNumeric(chars[i])) { - foundDigit = true; - allowSigns = false; - } else if (chars[i] == '.') { - if (hasDecPoint || hasExp) { - // two decimal points or dec in exponent - return false; - } - hasDecPoint = true; - } else if (chars[i] == 'e' || chars[i] == 'E') { - // we've already taken care of hex. - if (hasExp) { - // two E's - return false; - } - if (!foundDigit) { - return false; - } - hasExp = true; - allowSigns = true; - } else if (isSign(chars[i])) { - if (!allowSigns) { - return false; - } - allowSigns = false; - foundDigit = false; // we need a digit after the E - } else { - return false; - } - i++; - } - if (i < chars.length) { - if (CharUtils.isAsciiNumeric(chars[i])) { - // no type qualifier, OK - return true; - } - if (chars[i] == 'e' || chars[i] == 'E') { - // can't have an E at the last byte - return false; - } - if (chars[i] == '.') { - if (hasDecPoint || hasExp) { - // two decimal points or dec in exponent - return false; - } - // single trailing decimal point after non-exponent is ok - return foundDigit; - } - if (!allowSigns && (chars[i] == 'd' || chars[i] == 'D' || chars[i] == 'f' || chars[i] == 'F')) { - return foundDigit; - } - if (chars[i] == 'l' || chars[i] == 'L') { - // not allowing L with an exponent or decimal point - return foundDigit && !hasExp && !hasDecPoint; - } - // last character is illegal + try { + createNumber(str); + return true; + } catch (final RuntimeException e) { return false; } - // allowSigns is true iff the val ends in 'E' - // found digit it to make sure weird stuff like '.' and '1E-' doesn't pass - return !allowSigns && foundDigit; } /** diff --git a/src/test/java/org/apache/commons/lang3/math/NumberUtilsTest.java b/src/test/java/org/apache/commons/lang3/math/NumberUtilsTest.java index a41842c0d21..0cd9105af17 100644 --- a/src/test/java/org/apache/commons/lang3/math/NumberUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/math/NumberUtilsTest.java @@ -36,7 +36,9 @@ import java.util.function.Function; import org.apache.commons.lang3.AbstractLangTest; +import org.apache.commons.lang3.JavaVersion; import org.apache.commons.lang3.SystemProperties; +import org.apache.commons.lang3.SystemUtils; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -54,8 +56,7 @@ private static void assertCreateNumberZero(final String number, final Object zer private boolean checkCreateNumber(final String val) { try { - final Object obj = NumberUtils.createNumber(val); - return obj != null; + return NumberUtils.createNumber(val) != null; } catch (final NumberFormatException e) { return false; } @@ -887,6 +888,23 @@ void testIsCreatable() { compareIsCreatableWithCreateNumber(".D", false); // LANG-1646 compareIsCreatableWithCreateNumber(".e10", false); // LANG-1646 compareIsCreatableWithCreateNumber(".e10D", false); // LANG-1646 + compareIsCreatableWithCreateNumber("1E2147483647", true); + compareIsCreatableWithCreateNumber("1E+2147483647", true); + compareIsCreatableWithCreateNumber("1E-2147483647", true); + compareIsCreatableWithCreateNumber("1E-2147483648", false); + compareIsCreatableWithCreateNumber("1E2147483648", SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_21)); + compareIsCreatableWithCreateNumber("1E+2147483648", SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_21)); + compareIsCreatableWithCreateNumber("1E+2147483649", false); + compareIsCreatableWithCreateNumber("1E-2147483649", false); + compareIsCreatableWithCreateNumber("1E2147483648D", SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_21)); + compareIsCreatableWithCreateNumber("1E-2147483648D", false); + compareIsCreatableWithCreateNumber("1E2147483648F", SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_21)); + compareIsCreatableWithCreateNumber("1E+2147483648F", SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_21)); + compareIsCreatableWithCreateNumber("1E-2147483648F", false); + compareIsCreatableWithCreateNumber("1.0E2147483648", SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_21)); + compareIsCreatableWithCreateNumber("1.0E-2147483648", false); + compareIsCreatableWithCreateNumber("1E+999999999999999999999", false); + compareIsCreatableWithCreateNumber("1E-999999999999999999999", false); } @Test