001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.commons.lang;
018:
019: import java.math.BigDecimal;
020: import java.math.BigInteger;
021:
022: /**
023: * <p>Provides extra functionality for Java Number classes.</p>
024: *
025: * @author <a href="mailto:rand_mcneely@yahoo.com">Rand McNeely</a>
026: * @author Stephen Colebourne
027: * @author <a href="mailto:steve.downey@netfolio.com">Steve Downey</a>
028: * @author Eric Pugh
029: * @author Phil Steitz
030: * @since 1.0
031: * @version $Id: NumberUtils.java 488819 2006-12-19 21:50:04Z bayard $
032: *
033: * @deprecated Moved to org.apache.commons.lang.math.
034: * Class will be removed in Commons Lang 3.0.
035: */
036: public final class NumberUtils {
037: // DEPRECATED CLASS !!!
038:
039: /**
040: * <p><code>NumberUtils</code> instances should NOT be constructed in standard programming.
041: * Instead, the class should be used as <code>NumberUtils.stringToInt("6");</code>.</p>
042: *
043: * <p>This constructor is public to permit tools that require a JavaBean instance
044: * to operate.</p>
045: */
046: public NumberUtils() {
047: super ();
048: }
049:
050: //--------------------------------------------------------------------
051:
052: /**
053: * <p>Convert a <code>String</code> to an <code>int</code>, returning
054: * <code>zero</code> if the conversion fails.</p>
055: *
056: * @param str the string to convert
057: * @return the int represented by the string, or <code>zero</code> if
058: * conversion fails
059: */
060: public static int stringToInt(String str) {
061: return stringToInt(str, 0);
062: }
063:
064: /**
065: * <p>Convert a <code>String</code> to an <code>int</code>, returning a
066: * default value if the conversion fails.</p>
067: *
068: * @param str the string to convert
069: * @param defaultValue the default value
070: * @return the int represented by the string, or the default if conversion fails
071: */
072: public static int stringToInt(String str, int defaultValue) {
073: try {
074: return Integer.parseInt(str);
075: } catch (NumberFormatException nfe) {
076: return defaultValue;
077: }
078: }
079:
080: //--------------------------------------------------------------------
081:
082: // must handle Long, Float, Integer, Float, Short,
083: // BigDecimal, BigInteger and Byte
084: // useful methods:
085: // Byte.decode(String)
086: // Byte.valueOf(String,int radix)
087: // Byte.valueOf(String)
088: // Double.valueOf(String)
089: // Float.valueOf(String)
090: // new Float(String)
091: // Integer.valueOf(String,int radix)
092: // Integer.valueOf(String)
093: // Integer.decode(String)
094: // Integer.getInteger(String)
095: // Integer.getInteger(String,int val)
096: // Integer.getInteger(String,Integer val)
097: // new Integer(String)
098: // new Double(String)
099: // new Byte(String)
100: // new Long(String)
101: // Long.getLong(String)
102: // Long.getLong(String,int)
103: // Long.getLong(String,Integer)
104: // Long.valueOf(String,int)
105: // Long.valueOf(String)
106: // new Short(String)
107: // Short.decode(String)
108: // Short.valueOf(String,int)
109: // Short.valueOf(String)
110: // new BigDecimal(String)
111: // new BigInteger(String)
112: // new BigInteger(String,int radix)
113: // Possible inputs:
114: // 45 45.5 45E7 4.5E7 Hex Oct Binary xxxF xxxD xxxf xxxd
115: // plus minus everything. Prolly more. A lot are not separable.
116:
117: /**
118: * <p>Turns a string value into a java.lang.Number.</p>
119: *
120: * <p>First, the value is examined for a type qualifier on the end
121: * (<code>'f','F','d','D','l','L'</code>). If it is found, it starts
122: * trying to create successively larger types from the type specified
123: * until one is found that can hold the value.</p>
124: *
125: * <p>If a type specifier is not found, it will check for a decimal point
126: * and then try successively larger types from <code>Integer</code> to
127: * <code>BigInteger</code> and from <code>Float</code> to
128: * <code>BigDecimal</code>.</p>
129: *
130: * <p>If the string starts with <code>0x</code> or <code>-0x</code>, it
131: * will be interpreted as a hexadecimal integer. Values with leading
132: * <code>0</code>'s will not be interpreted as octal.</p>
133: *
134: * @param val String containing a number
135: * @return Number created from the string
136: * @throws NumberFormatException if the value cannot be converted
137: */
138: public static Number createNumber(String val)
139: throws NumberFormatException {
140: if (val == null) {
141: return null;
142: }
143: if (val.length() == 0) {
144: throw new NumberFormatException(
145: "\"\" is not a valid number.");
146: }
147: if (val.startsWith("--")) {
148: // this is protection for poorness in java.lang.BigDecimal.
149: // it accepts this as a legal value, but it does not appear
150: // to be in specification of class. OS X Java parses it to
151: // a wrong value.
152: return null;
153: }
154: if (val.startsWith("0x") || val.startsWith("-0x")) {
155: return createInteger(val);
156: }
157: char lastChar = val.charAt(val.length() - 1);
158: String mant;
159: String dec;
160: String exp;
161: int decPos = val.indexOf('.');
162: int expPos = val.indexOf('e') + val.indexOf('E') + 1;
163:
164: if (decPos > -1) {
165:
166: if (expPos > -1) {
167: if (expPos < decPos) {
168: throw new NumberFormatException(val
169: + " is not a valid number.");
170: }
171: dec = val.substring(decPos + 1, expPos);
172: } else {
173: dec = val.substring(decPos + 1);
174: }
175: mant = val.substring(0, decPos);
176: } else {
177: if (expPos > -1) {
178: mant = val.substring(0, expPos);
179: } else {
180: mant = val;
181: }
182: dec = null;
183: }
184: if (!Character.isDigit(lastChar)) {
185: if (expPos > -1 && expPos < val.length() - 1) {
186: exp = val.substring(expPos + 1, val.length() - 1);
187: } else {
188: exp = null;
189: }
190: //Requesting a specific type..
191: String numeric = val.substring(0, val.length() - 1);
192: boolean allZeros = isAllZeros(mant) && isAllZeros(exp);
193: switch (lastChar) {
194: case 'l':
195: case 'L':
196: if (dec == null
197: && exp == null
198: && (numeric.charAt(0) == '-'
199: && isDigits(numeric.substring(1)) || isDigits(numeric))) {
200: try {
201: return createLong(numeric);
202: } catch (NumberFormatException nfe) {
203: //Too big for a long
204: }
205: return createBigInteger(numeric);
206:
207: }
208: throw new NumberFormatException(val
209: + " is not a valid number.");
210: case 'f':
211: case 'F':
212: try {
213: Float f = NumberUtils.createFloat(numeric);
214: if (!(f.isInfinite() || (f.floatValue() == 0.0F && !allZeros))) {
215: //If it's too big for a float or the float value = 0 and the string
216: //has non-zeros in it, then float does not have the precision we want
217: return f;
218: }
219:
220: } catch (NumberFormatException e) {
221: // ignore the bad number
222: }
223: //Fall through
224: case 'd':
225: case 'D':
226: try {
227: Double d = NumberUtils.createDouble(numeric);
228: if (!(d.isInfinite() || (d.floatValue() == 0.0D && !allZeros))) {
229: return d;
230: }
231: } catch (NumberFormatException nfe) {
232: // empty catch
233: }
234: try {
235: return createBigDecimal(numeric);
236: } catch (NumberFormatException e) {
237: // empty catch
238: }
239: //Fall through
240: default:
241: throw new NumberFormatException(val
242: + " is not a valid number.");
243:
244: }
245: } else {
246: //User doesn't have a preference on the return type, so let's start
247: //small and go from there...
248: if (expPos > -1 && expPos < val.length() - 1) {
249: exp = val.substring(expPos + 1, val.length());
250: } else {
251: exp = null;
252: }
253: if (dec == null && exp == null) {
254: //Must be an int,long,bigint
255: try {
256: return createInteger(val);
257: } catch (NumberFormatException nfe) {
258: // empty catch
259: }
260: try {
261: return createLong(val);
262: } catch (NumberFormatException nfe) {
263: // empty catch
264: }
265: return createBigInteger(val);
266:
267: } else {
268: //Must be a float,double,BigDec
269: boolean allZeros = isAllZeros(mant) && isAllZeros(exp);
270: try {
271: Float f = createFloat(val);
272: if (!(f.isInfinite() || (f.floatValue() == 0.0F && !allZeros))) {
273: return f;
274: }
275: } catch (NumberFormatException nfe) {
276: // empty catch
277: }
278: try {
279: Double d = createDouble(val);
280: if (!(d.isInfinite() || (d.doubleValue() == 0.0D && !allZeros))) {
281: return d;
282: }
283: } catch (NumberFormatException nfe) {
284: // empty catch
285: }
286:
287: return createBigDecimal(val);
288:
289: }
290:
291: }
292: }
293:
294: /**
295: * <p>Utility method for {@link #createNumber(java.lang.String)}.</p>
296: *
297: * <p>Returns <code>true</code> if s is <code>null</code>.</p>
298: *
299: * @param s the String to check
300: * @return if it is all zeros or <code>null</code>
301: */
302: private static boolean isAllZeros(String s) {
303: if (s == null) {
304: return true;
305: }
306: for (int i = s.length() - 1; i >= 0; i--) {
307: if (s.charAt(i) != '0') {
308: return false;
309: }
310: }
311: return s.length() > 0;
312: }
313:
314: //--------------------------------------------------------------------
315:
316: /**
317: * <p>Convert a <code>String</code> to a <code>Float</code>.</p>
318: *
319: * @param val a <code>String</code> to convert
320: * @return converted <code>Float</code>
321: * @throws NumberFormatException if the value cannot be converted
322: */
323: public static Float createFloat(String val) {
324: return Float.valueOf(val);
325: }
326:
327: /**
328: * <p>Convert a <code>String</code> to a <code>Double</code>.</p>
329: *
330: * @param val a <code>String</code> to convert
331: * @return converted <code>Double</code>
332: * @throws NumberFormatException if the value cannot be converted
333: */
334: public static Double createDouble(String val) {
335: return Double.valueOf(val);
336: }
337:
338: /**
339: * <p>Convert a <code>String</code> to a <code>Integer</code>, handling
340: * hex and octal notations.</p>
341: *
342: * @param val a <code>String</code> to convert
343: * @return converted <code>Integer</code>
344: * @throws NumberFormatException if the value cannot be converted
345: */
346: public static Integer createInteger(String val) {
347: // decode() handles 0xAABD and 0777 (hex and octal) as well.
348: return Integer.decode(val);
349: }
350:
351: /**
352: * <p>Convert a <code>String</code> to a <code>Long</code>.</p>
353: *
354: * @param val a <code>String</code> to convert
355: * @return converted <code>Long</code>
356: * @throws NumberFormatException if the value cannot be converted
357: */
358: public static Long createLong(String val) {
359: return Long.valueOf(val);
360: }
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: /**
375: * <p>Convert a <code>String</code> to a <code>BigDecimal</code>.</p>
376: *
377: * @param val a <code>String</code> to convert
378: * @return converted <code>BigDecimal</code>
379: * @throws NumberFormatException if the value cannot be converted
380: */
381: public static BigDecimal createBigDecimal(String val) {
382: BigDecimal bd = new BigDecimal(val);
383: return bd;
384: }
385:
386: //--------------------------------------------------------------------
387:
388: /**
389: * <p>Gets the minimum of three <code>long</code> values.</p>
390: *
391: * @param a value 1
392: * @param b value 2
393: * @param c value 3
394: * @return the smallest of the values
395: */
396: public static long minimum(long a, long b, long c) {
397: if (b < a) {
398: a = b;
399: }
400: if (c < a) {
401: a = c;
402: }
403: return a;
404: }
405:
406: /**
407: * <p>Gets the minimum of three <code>int</code> values.</p>
408: *
409: * @param a value 1
410: * @param b value 2
411: * @param c value 3
412: * @return the smallest of the values
413: */
414: public static int minimum(int a, int b, int c) {
415: if (b < a) {
416: a = b;
417: }
418: if (c < a) {
419: a = c;
420: }
421: return a;
422: }
423:
424: /**
425: * <p>Gets the maximum of three <code>long</code> values.</p>
426: *
427: * @param a value 1
428: * @param b value 2
429: * @param c value 3
430: * @return the largest of the values
431: */
432: public static long maximum(long a, long b, long c) {
433: if (b > a) {
434: a = b;
435: }
436: if (c > a) {
437: a = c;
438: }
439: return a;
440: }
441:
442: /**
443: * <p>Gets the maximum of three <code>int</code> values.</p>
444: *
445: * @param a value 1
446: * @param b value 2
447: * @param c value 3
448: * @return the largest of the values
449: */
450: public static int maximum(int a, int b, int c) {
451: if (b > a) {
452: a = b;
453: }
454: if (c > a) {
455: a = c;
456: }
457: return a;
458: }
459:
460: //--------------------------------------------------------------------
461:
462: /**
463: * <p>Compares two <code>doubles</code> for order.</p>
464: *
465: * <p>This method is more comprehensive than the standard Java greater
466: * than, less than and equals operators.</p>
467: * <ul>
468: * <li>It returns <code>-1</code> if the first value is less than the second.
469: * <li>It returns <code>+1</code> if the first value is greater than the second.
470: * <li>It returns <code>0</code> if the values are equal.
471: * </ul>
472: *
473: * <p>
474: * The ordering is as follows, largest to smallest:
475: * <ul>
476: * <li>NaN
477: * <li>Positive infinity
478: * <li>Maximum double
479: * <li>Normal positive numbers
480: * <li>+0.0
481: * <li>-0.0
482: * <li>Normal negative numbers
483: * <li>Minimum double (-Double.MAX_VALUE)
484: * <li>Negative infinity
485: * </ul>
486: * </p>
487: *
488: * <p>Comparing <code>NaN</code> with <code>NaN</code> will
489: * return <code>0</code>.</p>
490: *
491: * @param lhs the first <code>double</code>
492: * @param rhs the second <code>double</code>
493: * @return <code>-1</code> if lhs is less, <code>+1</code> if greater,
494: * <code>0</code> if equal to rhs
495: */
496: public static int compare(double lhs, double rhs) {
497: if (lhs < rhs) {
498: return -1;
499: }
500: if (lhs > rhs) {
501: return +1;
502: }
503: // Need to compare bits to handle 0.0 == -0.0 being true
504: // compare should put -0.0 < +0.0
505: // Two NaNs are also == for compare purposes
506: // where NaN == NaN is false
507: long lhsBits = Double.doubleToLongBits(lhs);
508: long rhsBits = Double.doubleToLongBits(rhs);
509: if (lhsBits == rhsBits) {
510: return 0;
511: }
512: // Something exotic! A comparison to NaN or 0.0 vs -0.0
513: // Fortunately NaN's long is > than everything else
514: // Also negzeros bits < poszero
515: // NAN: 9221120237041090560
516: // MAX: 9218868437227405311
517: // NEGZERO: -9223372036854775808
518: if (lhsBits < rhsBits) {
519: return -1;
520: } else {
521: return +1;
522: }
523: }
524:
525: /**
526: * <p>Compares two floats for order.</p>
527: *
528: * <p>This method is more comprehensive than the standard Java greater than,
529: * less than and equals operators.</p>
530: * <ul>
531: * <li>It returns <code>-1</code> if the first value is less than the second.
532: * <li>It returns <code>+1</code> if the first value is greater than the second.
533: * <li>It returns <code>0</code> if the values are equal.
534: * </ul>
535: *
536: * <p> The ordering is as follows, largest to smallest:
537: * <ul>
538: * <li>NaN
539: * <li>Positive infinity
540: * <li>Maximum float
541: * <li>Normal positive numbers
542: * <li>+0.0
543: * <li>-0.0
544: * <li>Normal negative numbers
545: * <li>Minimum float (-Float.MAX_VALUE)
546: * <li>Negative infinity
547: * </ul>
548: *
549: * <p>Comparing <code>NaN</code> with <code>NaN</code> will return
550: * <code>0</code>.</p>
551: *
552: * @param lhs the first <code>float</code>
553: * @param rhs the second <code>float</code>
554: * @return <code>-1</code> if lhs is less, <code>+1</code> if greater,
555: * <code>0</code> if equal to rhs
556: */
557: public static int compare(float lhs, float rhs) {
558: if (lhs < rhs) {
559: return -1;
560: }
561: if (lhs > rhs) {
562: return +1;
563: }
564: //Need to compare bits to handle 0.0 == -0.0 being true
565: // compare should put -0.0 < +0.0
566: // Two NaNs are also == for compare purposes
567: // where NaN == NaN is false
568: int lhsBits = Float.floatToIntBits(lhs);
569: int rhsBits = Float.floatToIntBits(rhs);
570: if (lhsBits == rhsBits) {
571: return 0;
572: }
573: //Something exotic! A comparison to NaN or 0.0 vs -0.0
574: //Fortunately NaN's int is > than everything else
575: //Also negzeros bits < poszero
576: //NAN: 2143289344
577: //MAX: 2139095039
578: //NEGZERO: -2147483648
579: if (lhsBits < rhsBits) {
580: return -1;
581: } else {
582: return +1;
583: }
584: }
585:
586: //--------------------------------------------------------------------
587:
588: /**
589: * <p>Checks whether the <code>String</code> contains only
590: * digit characters.</p>
591: *
592: * <p><code>Null</code> and empty String will return
593: * <code>false</code>.</p>
594: *
595: * @param str the <code>String</code> to check
596: * @return <code>true</code> if str contains only unicode numeric
597: */
598: public static boolean isDigits(String str) {
599: if ((str == null) || (str.length() == 0)) {
600: return false;
601: }
602: for (int i = 0; i < str.length(); i++) {
603: if (!Character.isDigit(str.charAt(i))) {
604: return false;
605: }
606: }
607: return true;
608: }
609:
610: /**
611: * <p>Checks whether the String a valid Java number.</p>
612: *
613: * <p>Valid numbers include hexadecimal marked with the <code>0x</code>
614: * qualifier, scientific notation and numbers marked with a type
615: * qualifier (e.g. 123L).</p>
616: *
617: * <p><code>Null</code> and empty String will return
618: * <code>false</code>.</p>
619: *
620: * @param str the <code>String</code> to check
621: * @return <code>true</code> if the string is a correctly formatted number
622: */
623: public static boolean isNumber(String str) {
624: if (StringUtils.isEmpty(str)) {
625: return false;
626: }
627: char[] chars = str.toCharArray();
628: int sz = chars.length;
629: boolean hasExp = false;
630: boolean hasDecPoint = false;
631: boolean allowSigns = false;
632: boolean foundDigit = false;
633: // deal with any possible sign up front
634: int start = (chars[0] == '-') ? 1 : 0;
635: if (sz > start + 1) {
636: if (chars[start] == '0' && chars[start + 1] == 'x') {
637: int i = start + 2;
638: if (i == sz) {
639: return false; // str == "0x"
640: }
641: // checking hex (it can't be anything else)
642: for (; i < chars.length; i++) {
643: if ((chars[i] < '0' || chars[i] > '9')
644: && (chars[i] < 'a' || chars[i] > 'f')
645: && (chars[i] < 'A' || chars[i] > 'F')) {
646: return false;
647: }
648: }
649: return true;
650: }
651: }
652: sz--; // don't want to loop to the last char, check it afterwords
653: // for type qualifiers
654: int i = start;
655: // loop to the next to last char or to the last char if we need another digit to
656: // make a valid number (e.g. chars[0..5] = "1234E")
657: while (i < sz || (i < sz + 1 && allowSigns && !foundDigit)) {
658: if (chars[i] >= '0' && chars[i] <= '9') {
659: foundDigit = true;
660: allowSigns = false;
661:
662: } else if (chars[i] == '.') {
663: if (hasDecPoint || hasExp) {
664: // two decimal points or dec in exponent
665: return false;
666: }
667: hasDecPoint = true;
668: } else if (chars[i] == 'e' || chars[i] == 'E') {
669: // we've already taken care of hex.
670: if (hasExp) {
671: // two E's
672: return false;
673: }
674: if (!foundDigit) {
675: return false;
676: }
677: hasExp = true;
678: allowSigns = true;
679: } else if (chars[i] == '+' || chars[i] == '-') {
680: if (!allowSigns) {
681: return false;
682: }
683: allowSigns = false;
684: foundDigit = false; // we need a digit after the E
685: } else {
686: return false;
687: }
688: i++;
689: }
690: if (i < chars.length) {
691: if (chars[i] >= '0' && chars[i] <= '9') {
692: // no type qualifier, OK
693: return true;
694: }
695: if (chars[i] == 'e' || chars[i] == 'E') {
696: // can't have an E at the last byte
697: return false;
698: }
699: if (!allowSigns
700: && (chars[i] == 'd' || chars[i] == 'D'
701: || chars[i] == 'f' || chars[i] == 'F')) {
702: return foundDigit;
703: }
704: if (chars[i] == 'l' || chars[i] == 'L') {
705: // not allowing L with an exponent
706: return foundDigit && !hasExp;
707: }
708: // last character is illegal
709: return false;
710: }
711: // allowSigns is true iff the val ends in 'E'
712: // found digit it to make sure weird stuff like '.' and '1E-' doesn't pass
713: return !allowSigns && foundDigit;
714: }
715: }
|