28
28
import java .util .Set ;
29
29
import java .util .regex .Pattern ;
30
30
31
- import static org .json .NumberConversionUtil .potentialNumber ;
32
- import static org .json .NumberConversionUtil .stringToNumber ;
33
-
34
31
/**
35
32
* A JSONObject is an unordered collection of name/value pairs. Its external
36
33
* form is a string wrapped in curly braces with colons between the names and
@@ -2460,7 +2457,8 @@ public static Object stringToValue(String string) {
2460
2457
* produced, then the value will just be a string.
2461
2458
*/
2462
2459
2463
- if (potentialNumber (string )) {
2460
+ char initial = string .charAt (0 );
2461
+ if ((initial >= '0' && initial <= '9' ) || initial == '-' ) {
2464
2462
try {
2465
2463
return stringToNumber (string );
2466
2464
} catch (Exception ignore ) {
@@ -2469,8 +2467,75 @@ public static Object stringToValue(String string) {
2469
2467
return string ;
2470
2468
}
2471
2469
2472
-
2473
-
2470
+ /**
2471
+ * Converts a string to a number using the narrowest possible type. Possible
2472
+ * returns for this function are BigDecimal, Double, BigInteger, Long, and Integer.
2473
+ * When a Double is returned, it should always be a valid Double and not NaN or +-infinity.
2474
+ *
2475
+ * @param val value to convert
2476
+ * @return Number representation of the value.
2477
+ * @throws NumberFormatException thrown if the value is not a valid number. A public
2478
+ * caller should catch this and wrap it in a {@link JSONException} if applicable.
2479
+ */
2480
+ protected static Number stringToNumber (final String val ) throws NumberFormatException {
2481
+ char initial = val .charAt (0 );
2482
+ if ((initial >= '0' && initial <= '9' ) || initial == '-' ) {
2483
+ // decimal representation
2484
+ if (isDecimalNotation (val )) {
2485
+ // Use a BigDecimal all the time so we keep the original
2486
+ // representation. BigDecimal doesn't support -0.0, ensure we
2487
+ // keep that by forcing a decimal.
2488
+ try {
2489
+ BigDecimal bd = new BigDecimal (val );
2490
+ if (initial == '-' && BigDecimal .ZERO .compareTo (bd )==0 ) {
2491
+ return Double .valueOf (-0.0 );
2492
+ }
2493
+ return bd ;
2494
+ } catch (NumberFormatException retryAsDouble ) {
2495
+ // this is to support "Hex Floats" like this: 0x1.0P-1074
2496
+ try {
2497
+ Double d = Double .valueOf (val );
2498
+ if (d .isNaN () || d .isInfinite ()) {
2499
+ throw new NumberFormatException ("val [" +val +"] is not a valid number." );
2500
+ }
2501
+ return d ;
2502
+ } catch (NumberFormatException ignore ) {
2503
+ throw new NumberFormatException ("val [" +val +"] is not a valid number." );
2504
+ }
2505
+ }
2506
+ }
2507
+ // block items like 00 01 etc. Java number parsers treat these as Octal.
2508
+ if (initial == '0' && val .length () > 1 ) {
2509
+ char at1 = val .charAt (1 );
2510
+ if (at1 >= '0' && at1 <= '9' ) {
2511
+ throw new NumberFormatException ("val [" +val +"] is not a valid number." );
2512
+ }
2513
+ } else if (initial == '-' && val .length () > 2 ) {
2514
+ char at1 = val .charAt (1 );
2515
+ char at2 = val .charAt (2 );
2516
+ if (at1 == '0' && at2 >= '0' && at2 <= '9' ) {
2517
+ throw new NumberFormatException ("val [" +val +"] is not a valid number." );
2518
+ }
2519
+ }
2520
+ // integer representation.
2521
+ // This will narrow any values to the smallest reasonable Object representation
2522
+ // (Integer, Long, or BigInteger)
2523
+
2524
+ // BigInteger down conversion: We use a similar bitLength compare as
2525
+ // BigInteger#intValueExact uses. Increases GC, but objects hold
2526
+ // only what they need. i.e. Less runtime overhead if the value is
2527
+ // long lived.
2528
+ BigInteger bi = new BigInteger (val );
2529
+ if (bi .bitLength () <= 31 ){
2530
+ return Integer .valueOf (bi .intValue ());
2531
+ }
2532
+ if (bi .bitLength () <= 63 ){
2533
+ return Long .valueOf (bi .longValue ());
2534
+ }
2535
+ return bi ;
2536
+ }
2537
+ throw new NumberFormatException ("val [" +val +"] is not a valid number." );
2538
+ }
2474
2539
2475
2540
/**
2476
2541
* Throw an exception if the object is a NaN or infinite number.
@@ -2896,5 +2961,23 @@ private static JSONException recursivelyDefinedObjectException(String key) {
2896
2961
);
2897
2962
}
2898
2963
2899
-
2964
+ /**
2965
+ * For a prospective number, remove the leading zeros
2966
+ * @param value prospective number
2967
+ * @return number without leading zeros
2968
+ */
2969
+ private static String removeLeadingZerosOfNumber (String value ){
2970
+ if (value .equals ("-" )){return value ;}
2971
+ boolean negativeFirstChar = (value .charAt (0 ) == '-' );
2972
+ int counter = negativeFirstChar ? 1 :0 ;
2973
+ while (counter < value .length ()){
2974
+ if (value .charAt (counter ) != '0' ){
2975
+ if (negativeFirstChar ) {return "-" .concat (value .substring (counter ));}
2976
+ return value .substring (counter );
2977
+ }
2978
+ ++counter ;
2979
+ }
2980
+ if (negativeFirstChar ) {return "-0" ;}
2981
+ return "0" ;
2982
+ }
2900
2983
}
0 commit comments