1. /* ====================================================================
  2. * The Apache Software License, Version 1.1
  3. *
  4. * Copyright (c) 2002-2003 The Apache Software Foundation. All rights
  5. * reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. *
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in
  16. * the documentation and/or other materials provided with the
  17. * distribution.
  18. *
  19. * 3. The end-user documentation included with the redistribution, if
  20. * any, must include the following acknowledgement:
  21. * "This product includes software developed by the
  22. * Apache Software Foundation (http://www.apache.org/)."
  23. * Alternately, this acknowledgement may appear in the software itself,
  24. * if and wherever such third-party acknowledgements normally appear.
  25. *
  26. * 4. The names "The Jakarta Project", "Commons", and "Apache Software
  27. * Foundation" must not be used to endorse or promote products derived
  28. * from this software without prior written permission. For written
  29. * permission, please contact apache@apache.org.
  30. *
  31. * 5. Products derived from this software may not be called "Apache"
  32. * nor may "Apache" appear in their names without prior written
  33. * permission of the Apache Software Foundation.
  34. *
  35. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46. * SUCH DAMAGE.
  47. * ====================================================================
  48. *
  49. * This software consists of voluntary contributions made by many
  50. * individuals on behalf of the Apache Software Foundation. For more
  51. * information on the Apache Software Foundation, please see
  52. * <http://www.apache.org/>.
  53. */
  54. package org.apache.commons.lang;
  55. import java.math.BigDecimal;
  56. import java.math.BigInteger;
  57. /**
  58. * <p>Provides extra functionality for Java Number classes.</p>
  59. *
  60. * @author <a href="mailto:bayard@generationjava.com">Henri Yandell</a>
  61. * @author <a href="mailto:rand_mcneely@yahoo.com">Rand McNeely</a>
  62. * @author Stephen Colebourne
  63. * @author <a href="mailto:steve.downey@netfolio.com">Steve Downey</a>
  64. * @author Eric Pugh
  65. * @author Phil Steitz
  66. * @since 1.0
  67. * @version $Id: NumberUtils.java,v 1.14 2003/08/18 02:22:23 bayard Exp $
  68. *
  69. * @deprecated Moved to org.apache.commons.lang.math.
  70. * Class will be removed in Commons Lang 3.0.
  71. */
  72. public final class NumberUtils {
  73. // DEPRECATED CLASS !!!
  74. /**
  75. * <p><code>NumberUtils</code> instances should NOT be constructed in standard programming.
  76. * Instead, the class should be used as <code>NumberUtils.stringToInt("6");</code>.</p>
  77. *
  78. * <p>This constructor is public to permit tools that require a JavaBean instance
  79. * to operate.</p>
  80. */
  81. public NumberUtils() {
  82. }
  83. //--------------------------------------------------------------------
  84. /**
  85. * <p>Convert a <code>String</code> to an <code>int</code>, returning
  86. * <code>zero</code> if the conversion fails.</p>
  87. *
  88. * @param str the string to convert
  89. * @return the int represented by the string, or <code>zero</code> if
  90. * conversion fails
  91. */
  92. public static int stringToInt(String str) {
  93. return stringToInt(str, 0);
  94. }
  95. /**
  96. * <p>Convert a <code>String</code> to an <code>int</code>, returning a
  97. * default value if the conversion fails.</p>
  98. *
  99. * @param str the string to convert
  100. * @param defaultValue the default value
  101. * @return the int represented by the string, or the default if conversion fails
  102. */
  103. public static int stringToInt(String str, int defaultValue) {
  104. try {
  105. return Integer.parseInt(str);
  106. } catch (NumberFormatException nfe) {
  107. return defaultValue;
  108. }
  109. }
  110. //--------------------------------------------------------------------
  111. // must handle Long, Float, Integer, Float, Short,
  112. // BigDecimal, BigInteger and Byte
  113. // useful methods:
  114. // Byte.decode(String)
  115. // Byte.valueOf(String,int radix)
  116. // Byte.valueOf(String)
  117. // Double.valueOf(String)
  118. // Float.valueOf(String)
  119. // new Float(String)
  120. // Integer.valueOf(String,int radix)
  121. // Integer.valueOf(String)
  122. // Integer.decode(String)
  123. // Integer.getInteger(String)
  124. // Integer.getInteger(String,int val)
  125. // Integer.getInteger(String,Integer val)
  126. // new Integer(String)
  127. // new Double(String)
  128. // new Byte(String)
  129. // new Long(String)
  130. // Long.getLong(String)
  131. // Long.getLong(String,int)
  132. // Long.getLong(String,Integer)
  133. // Long.valueOf(String,int)
  134. // Long.valueOf(String)
  135. // new Short(String)
  136. // Short.decode(String)
  137. // Short.valueOf(String,int)
  138. // Short.valueOf(String)
  139. // new BigDecimal(String)
  140. // new BigInteger(String)
  141. // new BigInteger(String,int radix)
  142. // Possible inputs:
  143. // 45 45.5 45E7 4.5E7 Hex Oct Binary xxxF xxxD xxxf xxxd
  144. // plus minus everything. Prolly more. A lot are not separable.
  145. /**
  146. * <p>Turns a string value into a java.lang.Number.</p>
  147. *
  148. * <p>First, the value is examined for a type qualifier on the end
  149. * (<code>'f','F','d','D','l','L'</code>). If it is found, it starts
  150. * trying to create succissively larger types from the type specified
  151. * until one is found that can hold the value.</p>
  152. *
  153. * <p>If a type specifier is not found, it will check for a decimal point
  154. * and then try successively larger types from <code>Integer</code> to
  155. * <code>BigInteger</code> and from <code>Float</code> to
  156. * <code>BigDecimal</code>.</p>
  157. *
  158. * <p>If the string starts with <code>0x</code> or <code>-0x</code>, it
  159. * will be interpreted as a hexadecimal integer. Values with leading
  160. * <code>0</code>'s will not be interpreted as octal.</p>
  161. *
  162. * @param val String containing a number
  163. * @return Number created from the string
  164. * @throws NumberFormatException if the value cannot be converted
  165. */
  166. public static Number createNumber(String val) throws NumberFormatException {
  167. if (val == null) {
  168. return null;
  169. }
  170. if (val.length() == 0) {
  171. throw new NumberFormatException("\"\" is not a valid number.");
  172. }
  173. if (val.startsWith("--")) {
  174. // this is protection for poorness in java.lang.BigDecimal.
  175. // it accepts this as a legal value, but it does not appear
  176. // to be in specification of class. OS X Java parses it to
  177. // a wrong value.
  178. return null;
  179. }
  180. if (val.startsWith("0x") || val.startsWith("-0x")) {
  181. return createInteger(val);
  182. }
  183. char lastChar = val.charAt(val.length() - 1);
  184. String mant;
  185. String dec;
  186. String exp;
  187. int decPos = val.indexOf('.');
  188. int expPos = val.indexOf('e') + val.indexOf('E') + 1;
  189. if (decPos > -1) {
  190. if (expPos > -1) {
  191. if (expPos < decPos) {
  192. throw new NumberFormatException(val + " is not a valid number.");
  193. }
  194. dec = val.substring(decPos + 1, expPos);
  195. } else {
  196. dec = val.substring(decPos + 1);
  197. }
  198. mant = val.substring(0, decPos);
  199. } else {
  200. if (expPos > -1) {
  201. mant = val.substring(0, expPos);
  202. } else {
  203. mant = val;
  204. }
  205. dec = null;
  206. }
  207. if (!Character.isDigit(lastChar)) {
  208. if (expPos > -1 && expPos < val.length() - 1) {
  209. exp = val.substring(expPos + 1, val.length() - 1);
  210. } else {
  211. exp = null;
  212. }
  213. //Requesting a specific type..
  214. String numeric = val.substring(0, val.length() - 1);
  215. boolean allZeros = isAllZeros(mant) && isAllZeros(exp);
  216. switch (lastChar) {
  217. case 'l' :
  218. case 'L' :
  219. if (dec == null
  220. && exp == null
  221. && isDigits(numeric.substring(1))
  222. && (numeric.charAt(0) == '-' || Character.isDigit(numeric.charAt(0)))) {
  223. try {
  224. return createLong(numeric);
  225. } catch (NumberFormatException nfe) {
  226. //Too big for a long
  227. }
  228. return createBigInteger(numeric);
  229. }
  230. throw new NumberFormatException(val + " is not a valid number.");
  231. case 'f' :
  232. case 'F' :
  233. try {
  234. Float f = NumberUtils.createFloat(numeric);
  235. if (!(f.isInfinite() || (f.floatValue() == 0.0F && !allZeros))) {
  236. //If it's too big for a float or the float value = 0 and the string
  237. //has non-zeros in it, then float doens't have the presision we want
  238. return f;
  239. }
  240. } catch (NumberFormatException nfe) {
  241. }
  242. //Fall through
  243. case 'd' :
  244. case 'D' :
  245. try {
  246. Double d = NumberUtils.createDouble(numeric);
  247. if (!(d.isInfinite() || (d.floatValue() == 0.0D && !allZeros))) {
  248. return d;
  249. }
  250. } catch (NumberFormatException nfe) {
  251. }
  252. try {
  253. return createBigDecimal(numeric);
  254. } catch (NumberFormatException e) {
  255. }
  256. //Fall through
  257. default :
  258. throw new NumberFormatException(val + " is not a valid number.");
  259. }
  260. } else {
  261. //User doesn't have a preference on the return type, so let's start
  262. //small and go from there...
  263. if (expPos > -1 && expPos < val.length() - 1) {
  264. exp = val.substring(expPos + 1, val.length());
  265. } else {
  266. exp = null;
  267. }
  268. if (dec == null && exp == null) {
  269. //Must be an int,long,bigint
  270. try {
  271. return createInteger(val);
  272. } catch (NumberFormatException nfe) {
  273. }
  274. try {
  275. return createLong(val);
  276. } catch (NumberFormatException nfe) {
  277. }
  278. return createBigInteger(val);
  279. } else {
  280. //Must be a float,double,BigDec
  281. boolean allZeros = isAllZeros(mant) && isAllZeros(exp);
  282. try {
  283. Float f = createFloat(val);
  284. if (!(f.isInfinite() || (f.floatValue() == 0.0F && !allZeros))) {
  285. return f;
  286. }
  287. } catch (NumberFormatException nfe) {
  288. }
  289. try {
  290. Double d = createDouble(val);
  291. if (!(d.isInfinite() || (d.doubleValue() == 0.0D && !allZeros))) {
  292. return d;
  293. }
  294. } catch (NumberFormatException nfe) {
  295. }
  296. return createBigDecimal(val);
  297. }
  298. }
  299. }
  300. /**
  301. * <p>Utility method for {@link #createNumber(java.lang.String)}.</p>
  302. *
  303. * <p>Returns <code>true</code> if s is <code>null</code>.</p>
  304. *
  305. * @param s the String to check
  306. * @return if it is all zeros or <code>null</code>
  307. */
  308. private static boolean isAllZeros(String s) {
  309. if (s == null) {
  310. return true;
  311. }
  312. for (int i = s.length() - 1; i >= 0; i--) {
  313. if (s.charAt(i) != '0') {
  314. return false;
  315. }
  316. }
  317. return s.length() > 0;
  318. }
  319. //--------------------------------------------------------------------
  320. /**
  321. * <p>Convert a <code>String</code> to a <code>Float</code>.</p>
  322. *
  323. * @param val a <code>String</code> to convert
  324. * @return converted <code>Float</code>
  325. * @throws NumberFormatException if the value cannot be converted
  326. */
  327. public static Float createFloat(String val) {
  328. return Float.valueOf(val);
  329. }
  330. /**
  331. * <p>Convert a <code>String</code> to a <code>Double</code>.</p>
  332. *
  333. * @param val a <code>String</code> to convert
  334. * @return converted <code>Double</code>
  335. * @throws NumberFormatException if the value cannot be converted
  336. */
  337. public static Double createDouble(String val) {
  338. return Double.valueOf(val);
  339. }
  340. /**
  341. * <p>Convert a <code>String</code> to a <code>Integer</code>, handling
  342. * hex and octal notations.</p>
  343. *
  344. * @param val a <code>String</code> to convert
  345. * @return converted <code>Integer</code>
  346. * @throws NumberFormatException if the value cannot be converted
  347. */
  348. public static Integer createInteger(String val) {
  349. // decode() handles 0xAABD and 0777 (hex and octal) as well.
  350. return Integer.decode(val);
  351. }
  352. /**
  353. * <p>Convert a <code>String</code> to a <code>Long</code>.</p>
  354. *
  355. * @param val a <code>String</code> to convert
  356. * @return converted <code>Long</code>
  357. * @throws NumberFormatException if the value cannot be converted
  358. */
  359. public static Long createLong(String val) {
  360. return Long.valueOf(val);
  361. }
  362. /**
  363. * <p>Convert a <code>String</code> to a <code>BigInteger</code>.</p>
  364. *
  365. * @param val a <code>String</code> to convert
  366. * @return converted <code>BigInteger</code>
  367. * @throws NumberFormatException if the value cannot be converted
  368. */
  369. public static BigInteger createBigInteger(String val) {
  370. BigInteger bi = new BigInteger(val);
  371. return bi;
  372. }
  373. /**
  374. * <p>Convert a <code>String</code> to a <code>BigDecimal</code>.</p>
  375. *
  376. * @param val a <code>String</code> to convert
  377. * @return converted <code>BigDecimal</code>
  378. * @throws NumberFormatException if the value cannot be converted
  379. */
  380. public static BigDecimal createBigDecimal(String val) {
  381. BigDecimal bd = new BigDecimal(val);
  382. return bd;
  383. }
  384. //--------------------------------------------------------------------
  385. /**
  386. * <p>Gets the minimum of three <code>long</code> values.</p>
  387. *
  388. * @param a value 1
  389. * @param b value 2
  390. * @param c value 3
  391. * @return the smallest of the values
  392. */
  393. public static long minimum(long a, long b, long c) {
  394. if (b < a) {
  395. a = b;
  396. }
  397. if (c < a) {
  398. a = c;
  399. }
  400. return a;
  401. }
  402. /**
  403. * <p>Gets the minimum of three <code>int</code> values.</p>
  404. *
  405. * @param a value 1
  406. * @param b value 2
  407. * @param c value 3
  408. * @return the smallest of the values
  409. */
  410. public static int minimum(int a, int b, int c) {
  411. if (b < a) {
  412. a = b;
  413. }
  414. if (c < a) {
  415. a = c;
  416. }
  417. return a;
  418. }
  419. /**
  420. * <p>Gets the maximum of three <code>long</code> values.</p>
  421. *
  422. * @param a value 1
  423. * @param b value 2
  424. * @param c value 3
  425. * @return the largest of the values
  426. */
  427. public static long maximum(long a, long b, long c) {
  428. if (b > a) {
  429. a = b;
  430. }
  431. if (c > a) {
  432. a = c;
  433. }
  434. return a;
  435. }
  436. /**
  437. * <p>Gets the maximum of three <code>int</code> values.</p>
  438. *
  439. * @param a value 1
  440. * @param b value 2
  441. * @param c value 3
  442. * @return the largest of the values
  443. */
  444. public static int maximum(int a, int b, int c) {
  445. if (b > a) {
  446. a = b;
  447. }
  448. if (c > a) {
  449. a = c;
  450. }
  451. return a;
  452. }
  453. //--------------------------------------------------------------------
  454. /**
  455. * <p>Compares two <code>doubles</code> for order.</p>
  456. *
  457. * <p>This method is more comprehensive than the standard Java greater
  458. * than, less than and equals operators.</p>
  459. * <ul>
  460. * <li>It returns <code>-1</code> if the first value is less than the second.
  461. * <li>It returns <code>+1</code> if the first value is greater than the second.
  462. * <li>It returns <code>0</code> if the values are equal.
  463. * </ul>
  464. *
  465. * <p>
  466. * The ordering is as follows, largest to smallest:
  467. * <ul>
  468. * <li>NaN
  469. * <li>Positive infinity
  470. * <li>Maximum double
  471. * <li>Normal positve numbers
  472. * <li>+0.0
  473. * <li>-0.0
  474. * <li>Normal negative numbers
  475. * <li>Minimum double (-Double.MAX_VALUE)
  476. * <li>Negative infinity
  477. * </ul>
  478. * </p>
  479. *
  480. * <p>Comparing <code>NaN</code> with <code>NaN</code> will
  481. * return <code>0</code>.</p>
  482. *
  483. * @param lhs the first <code>double</code>
  484. * @param rhs the second <code>double</code>
  485. * @return <code>-1</code> if lhs is less, <code>+1</code> if greater,
  486. * <code>0</code> if equal to rhs
  487. */
  488. public static int compare(double lhs, double rhs) {
  489. if (lhs < rhs) {
  490. return -1;
  491. }
  492. if (lhs > rhs) {
  493. return +1;
  494. }
  495. // Need to compare bits to handle 0.0 == -0.0 being true
  496. // compare should put -0.0 < +0.0
  497. // Two NaNs are also == for compare purposes
  498. // where NaN == NaN is false
  499. long lhsBits = Double.doubleToLongBits(lhs);
  500. long rhsBits = Double.doubleToLongBits(rhs);
  501. if (lhsBits == rhsBits) {
  502. return 0;
  503. }
  504. // Something exotic! A comparison to NaN or 0.0 vs -0.0
  505. // Fortunately NaN's long is > than everything else
  506. // Also negzeros bits < poszero
  507. // NAN: 9221120237041090560
  508. // MAX: 9218868437227405311
  509. // NEGZERO: -9223372036854775808
  510. if (lhsBits < rhsBits) {
  511. return -1;
  512. } else {
  513. return +1;
  514. }
  515. }
  516. /**
  517. * <p>Compares two floats for order.</p>
  518. *
  519. * <p>This method is more comprhensive than the standard Java greater than,
  520. * less than and equals operators.</p>
  521. * <ul>
  522. * <li>It returns <code>-1</code> if the first value is less than the second.
  523. * <li>It returns <code>+1</code> if the first value is greater than the second.
  524. * <li>It returns <code>0</code> if the values are equal.
  525. * </ul>
  526. *
  527. * <p> The ordering is as follows, largest to smallest:
  528. * <ul>
  529. * <li>NaN
  530. * <li>Positive infinity
  531. * <li>Maximum float
  532. * <li>Normal positve numbers
  533. * <li>+0.0
  534. * <li>-0.0
  535. * <li>Normal negative numbers
  536. * <li>Minimum float (-Float.MAX_VALUE)
  537. * <li>Negative infinity
  538. * </ul>
  539. *
  540. * <p>Comparing <code>NaN</code> with <code>NaN</code> will return
  541. * <code>0</code>.</p>
  542. *
  543. * @param lhs the first <code>float</code>
  544. * @param rhs the second <code>float</code>
  545. * @return <code>-1</code> if lhs is less, <code>+1</code> if greater,
  546. * <code>0</code> if equal to rhs
  547. */
  548. public static int compare(float lhs, float rhs) {
  549. if (lhs < rhs) {
  550. return -1;
  551. }
  552. if (lhs > rhs) {
  553. return +1;
  554. }
  555. //Need to compare bits to handle 0.0 == -0.0 being true
  556. // compare should put -0.0 < +0.0
  557. // Two NaNs are also == for compare purposes
  558. // where NaN == NaN is false
  559. int lhsBits = Float.floatToIntBits(lhs);
  560. int rhsBits = Float.floatToIntBits(rhs);
  561. if (lhsBits == rhsBits) {
  562. return 0;
  563. }
  564. //Something exotic! A comparison to NaN or 0.0 vs -0.0
  565. //Fortunately NaN's int is > than everything else
  566. //Also negzeros bits < poszero
  567. //NAN: 2143289344
  568. //MAX: 2139095039
  569. //NEGZERO: -2147483648
  570. if (lhsBits < rhsBits) {
  571. return -1;
  572. } else {
  573. return +1;
  574. }
  575. }
  576. //--------------------------------------------------------------------
  577. /**
  578. * <p>Checks whether the <code>String</code> contains only
  579. * digit characters.</p>
  580. *
  581. * <p><code>Null</code> and empty String will return
  582. * <code>false</code>.</p>
  583. *
  584. * @param str the <code>String</code> to check
  585. * @return <code>true</code> if str contains only unicode numeric
  586. */
  587. public static boolean isDigits(String str) {
  588. if ((str == null) || (str.length() == 0)) {
  589. return false;
  590. }
  591. for (int i = 0; i < str.length(); i++) {
  592. if (!Character.isDigit(str.charAt(i))) {
  593. return false;
  594. }
  595. }
  596. return true;
  597. }
  598. /**
  599. * <p>Checks whether the String a valid Java number.</p>
  600. *
  601. * <p>Valid numbers include hexadecimal marked with the <code>0x</code>
  602. * qualifier, scientific notation and numbers marked with a type
  603. * qualifier (e.g. 123L).</p>
  604. *
  605. * <p><code>Null</code> and empty String will return
  606. * <code>false</code>.</p>
  607. *
  608. * @param str the <code>String</code> to check
  609. * @return <code>true</code> if the string is a correctly formatted number
  610. */
  611. public static boolean isNumber(String str) {
  612. if ((str == null) || (str.length() == 0)) {
  613. return false;
  614. }
  615. char[] chars = str.toCharArray();
  616. int sz = chars.length;
  617. boolean hasExp = false;
  618. boolean hasDecPoint = false;
  619. boolean allowSigns = false;
  620. boolean foundDigit = false;
  621. // deal with any possible sign up front
  622. int start = (chars[0] == '-') ? 1 : 0;
  623. if (sz > start + 1) {
  624. if (chars[start] == '0' && chars[start + 1] == 'x') {
  625. int i = start + 2;
  626. if (i == sz) {
  627. return false; // str == "0x"
  628. }
  629. // checking hex (it can't be anything else)
  630. for (; i < chars.length; i++) {
  631. if ((chars[i] < '0' || chars[i] > '9')
  632. && (chars[i] < 'a' || chars[i] > 'f')
  633. && (chars[i] < 'A' || chars[i] > 'F')) {
  634. return false;
  635. }
  636. }
  637. return true;
  638. }
  639. }
  640. sz--; // don't want to loop to the last char, check it afterwords
  641. // for type qualifiers
  642. int i = start;
  643. // loop to the next to last char or to the last char if we need another digit to
  644. // make a valid number (e.g. chars[0..5] = "1234E")
  645. while (i < sz || (i < sz + 1 && allowSigns && !foundDigit)) {
  646. if (chars[i] >= '0' && chars[i] <= '9') {
  647. foundDigit = true;
  648. allowSigns = false;
  649. } else if (chars[i] == '.') {
  650. if (hasDecPoint || hasExp) {
  651. // two decimal points or dec in exponent
  652. return false;
  653. }
  654. hasDecPoint = true;
  655. } else if (chars[i] == 'e' || chars[i] == 'E') {
  656. // we've already taken care of hex.
  657. if (hasExp) {
  658. // two E's
  659. return false;
  660. }
  661. if (!foundDigit) {
  662. return false;
  663. }
  664. hasExp = true;
  665. allowSigns = true;
  666. } else if (chars[i] == '+' || chars[i] == '-') {
  667. if (!allowSigns) {
  668. return false;
  669. }
  670. allowSigns = false;
  671. foundDigit = false; // we need a digit after the E
  672. } else {
  673. return false;
  674. }
  675. i++;
  676. }
  677. if (i < chars.length) {
  678. if (chars[i] >= '0' && chars[i] <= '9') {
  679. // no type qualifier, OK
  680. return true;
  681. }
  682. if (chars[i] == 'e' || chars[i] == 'E') {
  683. // can't have an E at the last byte
  684. return false;
  685. }
  686. if (!allowSigns
  687. && (chars[i] == 'd'
  688. || chars[i] == 'D'
  689. || chars[i] == 'f'
  690. || chars[i] == 'F')) {
  691. return foundDigit;
  692. }
  693. if (chars[i] == 'l'
  694. || chars[i] == 'L') {
  695. // not allowing L with an exponoent
  696. return foundDigit && !hasExp;
  697. }
  698. // last character is illegal
  699. return false;
  700. }
  701. // allowSigns is true iff the val ends in 'E'
  702. // found digit it to make sure weird stuff like '.' and '1E-' doesn't pass
  703. return !allowSigns && foundDigit;
  704. }
  705. }