Java tutorial
//package com.java2s; /* * Copyright Aduna (http://www.aduna-software.com/) (c) 1997-2007. * * Licensed under the Aduna BSD-style license. */ import java.util.StringTokenizer; public class Main { /** * Normalizes a double to its canonical representation. * * @param value * The value to normalize. * @return The canonical representation of <tt>value</tt>. * @throws IllegalArgumentException * If the supplied value is not a legal double. */ public static String normalizeDouble(String value) { return normalizeFPNumber(value, "-9007199254740991.0", "9007199254740991.0", "-1075", "970"); } /** * Normalizes a floating point number to its canonical representation. * * @param value * The value to normalize. * @return The canonical representation of <tt>value</tt>. * @throws IllegalArgumentException * If the supplied value is not a legal floating point number. */ public static String normalizeFPNumber(String value) { return normalizeFPNumber(value, null, null, null, null); } /** * Normalizes a floating point number to its canonical representation. * * @param value * The value to normalize. * @param minMantissa * A normalized decimal indicating the lowest value that the * mantissa may have. * @param maxMantissa * A normalized decimal indicating the highest value that the * mantissa may have. * @param minExponent * A normalized integer indicating the lowest value that the * exponent may have. * @param maxExponent * A normalized integer indicating the highest value that the * exponent may have. * @return The canonical representation of <tt>value</tt>. * @throws IllegalArgumentException * If the supplied value is not a legal floating point number. */ private static String normalizeFPNumber(String value, String minMantissa, String maxMantissa, String minExponent, String maxExponent) { value = collapseWhiteSpace(value); // handle special values if (value.equals("INF") || value.equals("-INF") || value.equals("NaN")) { return value; } // Search for the exponent character E or e int eIdx = value.indexOf('E'); if (eIdx == -1) { // try lower case eIdx = value.indexOf('e'); } // Extract mantissa and exponent String mantissa, exponent; if (eIdx == -1) { mantissa = normalizeDecimal(value); exponent = "0"; } else { mantissa = normalizeDecimal(value.substring(0, eIdx)); exponent = normalizeInteger(value.substring(eIdx + 1)); } // Check lower and upper bounds, if applicable if (minMantissa != null) { if (compareCanonicalDecimals(mantissa, minMantissa) < 0) { throwIAE("Mantissa smaller than minimum value (" + minMantissa + ")"); } } if (maxMantissa != null) { if (compareCanonicalDecimals(mantissa, maxMantissa) > 0) { throwIAE("Mantissa larger than maximum value (" + maxMantissa + ")"); } } if (minExponent != null) { if (compareCanonicalIntegers(exponent, minExponent) < 0) { throwIAE("Exponent smaller than minimum value (" + minExponent + ")"); } } if (maxExponent != null) { if (compareCanonicalIntegers(exponent, maxExponent) > 0) { throwIAE("Exponent larger than maximum value (" + maxExponent + ")"); } } // Normalize mantissa to one non-zero digit before the dot int shift = 0; int dotIdx = mantissa.indexOf('.'); int digitCount = dotIdx; if (mantissa.charAt(0) == '-') { digitCount--; } if (digitCount > 1) { // more than one digit before the dot, e.g 123.45, -10.0 or 100.0 StringBuilder sb = new StringBuilder(mantissa.length()); int firstDigitIdx = 0; if (mantissa.charAt(0) == '-') { sb.append('-'); firstDigitIdx = 1; } sb.append(mantissa.charAt(firstDigitIdx)); sb.append('.'); sb.append(mantissa.substring(firstDigitIdx + 1, dotIdx)); sb.append(mantissa.substring(dotIdx + 1)); mantissa = sb.toString(); // Check if the mantissa has excessive trailing zeros. // For example, 100.0 will be normalize to 1.000 and // -10.0 to -1.00. int nonZeroIdx = mantissa.length() - 1; while (nonZeroIdx >= 3 && mantissa.charAt(nonZeroIdx) == '0') { nonZeroIdx--; } if (nonZeroIdx < 3 && mantissa.charAt(0) == '-') { nonZeroIdx++; } if (nonZeroIdx < mantissa.length() - 1) { mantissa = mantissa.substring(0, nonZeroIdx + 1); } shift = 1 - digitCount; } else if (mantissa.startsWith("0.") || mantissa.startsWith("-0.")) { // Example mantissas: 0.0, -0.1, 0.00345 and 0.09 // search first non-zero digit int nonZeroIdx = 2; while (nonZeroIdx < mantissa.length() && mantissa.charAt(nonZeroIdx) == '0') { nonZeroIdx++; } // 0.0 does not need any normalization: if (nonZeroIdx < mantissa.length()) { StringBuilder sb = new StringBuilder(mantissa.length()); sb.append(mantissa.charAt(nonZeroIdx)); sb.append('.'); if (nonZeroIdx == mantissa.length() - 1) { // There was only one non-zero digit, e.g. as in 0.09 sb.append('0'); } else { sb.append(mantissa.substring(nonZeroIdx + 1)); } mantissa = sb.toString(); shift = nonZeroIdx - 1; } } if (shift != 0) { try { int exp = Integer.parseInt(exponent); exponent = String.valueOf(exp - shift); } catch (NumberFormatException e) { throw new RuntimeException("NumberFormatException: " + e.getMessage()); } } return mantissa + "E" + exponent; } /** * Replaces all contiguous sequences of #x9 (tab), #xA (line feed) and #xD * (carriage return) with a single #x20 (space) character, and removes any * leading and trailing whitespace characters, as specified for whiteSpace * facet <tt>collapse</tt>. */ public static String collapseWhiteSpace(String s) { StringBuilder sb = new StringBuilder(s.length()); StringTokenizer st = new StringTokenizer(s, "\t\r\n "); if (st.hasMoreTokens()) { sb.append(st.nextToken()); } while (st.hasMoreTokens()) { sb.append(' ').append(st.nextToken()); } return sb.toString(); } /** * Normalizes a decimal to its canonical representation. For example: * <tt>120</tt> becomes <tt>120.0</tt>, <tt>+.3</tt> becomes <tt>0.3</tt>, * <tt>00012.45000</tt> becomes <tt>12.45</tt> and <tt>-.0</tt> becomes * <tt>0.0</tt>. * * @param decimal * The decimal to normalize. * @return The canonical representation of <tt>decimal</tt>. * @throws IllegalArgumentException * If one of the supplied strings is not a legal decimal. */ public static String normalizeDecimal(String decimal) { decimal = collapseWhiteSpace(decimal); int decLength = decimal.length(); StringBuilder result = new StringBuilder(decLength + 2); if (decLength == 0) { throwIAE("Not a legal decimal: " + decimal); } boolean isZeroPointZero = true; // process any sign info int idx = 0; if (decimal.charAt(idx) == '-') { result.append('-'); idx++; } else if (decimal.charAt(idx) == '+') { idx++; } if (idx == decLength) { throwIAE("Not a legal decimal: " + decimal); } // skip any leading zeros while (idx < decLength && decimal.charAt(idx) == '0') { idx++; } // Process digits before the dot if (idx == decLength) { // decimal consists of zeros only result.append('0'); } else if (idx < decLength && decimal.charAt(idx) == '.') { // no non-zero digit before the dot result.append('0'); } else { isZeroPointZero = false; // Copy any digits before the dot while (idx < decLength) { char c = decimal.charAt(idx); if (c == '.') { break; } if (!isDigit(c)) { throwIAE("Not a legal decimal: " + decimal); } result.append(c); idx++; } } result.append('.'); // Process digits after the dot if (idx == decLength) { // No dot was found in the decimal result.append('0'); } else { idx++; // search last non-zero digit int lastIdx = decLength - 1; while (lastIdx >= 0 && decimal.charAt(lastIdx) == '0') { lastIdx--; } if (idx > lastIdx) { // No non-zero digits found result.append('0'); } else { isZeroPointZero = false; while (idx <= lastIdx) { char c = decimal.charAt(idx); if (!isDigit(c)) { throwIAE("Not a legal decimal: " + decimal); } result.append(c); idx++; } } } if (isZeroPointZero) { // Make sure we don't return "-0.0" return "0.0"; } else { return result.toString(); } } /** * Normalizes an integer to its canonical representation. For example: * <tt>+120</tt> becomes <tt>120</tt> and <tt>00012</tt> becomes <tt>12</tt> * . * * @param value * The value to normalize. * @return The canonical representation of <tt>value</tt>. * @throws IllegalArgumentException * If the supplied value is not a legal integer. */ public static String normalizeInteger(String value) { return normalizeIntegerValue(value, null, null); } /** * Compares two canonical decimals to eachother. * * @return A negative number if <tt>dec1</tt> is smaller than <tt>dec2</tt>, * <tt>0</tt> if they are equal, or positive (>0) if * <tt>dec1</tt> is larger than <tt>dec2</tt>. The result is * undefined when one or both of the arguments is not a canonical * decimal. * @throws IllegalArgumentException * If one of the supplied strings is not a legal decimal. */ public static int compareCanonicalDecimals(String dec1, String dec2) { if (dec1.equals(dec2)) { return 0; } // Check signs if (dec1.charAt(0) == '-' && dec2.charAt(0) != '-') { // dec1 is negative, dec2 is not return -1; } if (dec2.charAt(0) == '-' && dec1.charAt(0) != '-') { // dec2 is negative, dec1 is not return 1; } int dotIdx1 = dec1.indexOf('.'); int dotIdx2 = dec2.indexOf('.'); // The decimal with the most digits before the dot is the largest int result = dotIdx1 - dotIdx2; if (result == 0) { // equal number of digits before the dot, compare them for (int i = 0; result == 0 && i < dotIdx1; i++) { result = dec1.charAt(i) - dec2.charAt(i); } // Continue comparing digits after the dot if necessary int dec1Length = dec1.length(); int dec2Length = dec2.length(); int lastIdx = dec1Length <= dec2Length ? dec1Length : dec2Length; for (int i = dotIdx1 + 1; result == 0 && i < lastIdx; i++) { result = dec1.charAt(i) - dec2.charAt(i); } // Still equal? The decimal with the most digits is the largest if (result == 0) { result = dec1Length - dec2Length; } } if (dec1.charAt(0) == '-') { // reverse result for negative values result = -result; } return result; } /** * Throws an IllegalArgumentException that contains the supplied message. */ private static final void throwIAE(String msg) { throw new IllegalArgumentException(msg); } /** * Compares two canonical integers to eachother. * * @return A negative number if <tt>int1</tt> is smaller than <tt>int2</tt>, * <tt>0</tt> if they are equal, or positive (>0) if * <tt>int1</tt> is larger than <tt>int2</tt>. The result is * undefined when one or both of the arguments is not a canonical * integer. * @throws IllegalArgumentException * If one of the supplied strings is not a legal integer. */ public static int compareCanonicalIntegers(String int1, String int2) { if (int1.equals(int2)) { return 0; } // Check signs if (int1.charAt(0) == '-' && int2.charAt(0) != '-') { // int1 is negative, int2 is not return -1; } if (int2.charAt(0) == '-' && int1.charAt(0) != '-') { // int2 is negative, int1 is not return 1; } // The integer with the most digits is the largest int result = int1.length() - int2.length(); if (result == 0) { // equal number of digits, compare them for (int i = 0; result == 0 && i < int1.length(); i++) { result = int1.charAt(i) - int2.charAt(i); } } if (int1.charAt(0) == '-') { // reverse result for negative values result = -result; } return result; } /** * Parses the supplied xsd:int strings and returns its value. * * @param s * A string representation of an xsd:int value. * @return The <tt>int</tt> value represented by the supplied string * argument. * @throws NumberFormatException * If the supplied string is not a valid xsd:int value. */ public static int parseInt(String s) { s = trimPlusSign(s); return Integer.parseInt(s); } /** * Checks whether the supplied character is a digit. */ private static final boolean isDigit(char c) { return c >= '0' && c <= '9'; } /** * Normalizes an integer to its canonical representation and checks that the * value is in the range [minValue, maxValue]. */ private static String normalizeIntegerValue(String integer, String minValue, String maxValue) { integer = collapseWhiteSpace(integer); int intLength = integer.length(); if (intLength == 0) { throwIAE("Not a legal integer: " + integer); } int idx = 0; // process any sign info boolean isNegative = false; if (integer.charAt(idx) == '-') { isNegative = true; idx++; } else if (integer.charAt(idx) == '+') { idx++; } if (idx == intLength) { throwIAE("Not a legal integer: " + integer); } if (integer.charAt(idx) == '0' && idx < intLength - 1) { // integer starts with a zero followed by more characters, // skip any leading zeros idx++; while (idx < intLength - 1 && integer.charAt(idx) == '0') { idx++; } } String norm = integer.substring(idx); // Check that all characters in 'norm' are digits for (int i = 0; i < norm.length(); i++) { if (!isDigit(norm.charAt(i))) { throwIAE("Not a legal integer: " + integer); } } if (isNegative && norm.charAt(0) != '0') { norm = "-" + norm; } // Check lower and upper bounds, if applicable if (minValue != null) { if (compareCanonicalIntegers(norm, minValue) < 0) { throwIAE("Value smaller than minimum value"); } } if (maxValue != null) { if (compareCanonicalIntegers(norm, maxValue) > 0) { throwIAE("Value larger than maximum value"); } } return norm; } /** * Removes the first character from the supplied string if this is a plus * sign ('+'). Number strings with leading plus signs cannot be parsed by * methods such as {@link Integer#parseInt(String)}. */ private static String trimPlusSign(String s) { if (s.length() > 0 && s.charAt(0) == '+') { return s.substring(1); } else { return s; } } }