📄 decimalformat.java
字号:
if (isNegative) { append(result, negativeSuffix, delegate, getNegativeSuffixFieldPositions(), Field.SIGN); } else { append(result, positiveSuffix, delegate, getPositiveSuffixFieldPositions(), Field.SIGN); } return result; } /** * Appends the String <code>string</code> to <code>result</code>. * <code>delegate</code> is notified of all the * <code>FieldPosition</code>s in <code>positions</code>. * <p> * If one of the <code>FieldPosition</code>s in <code>positions</code> * identifies a <code>SIGN</code> attribute, it is mapped to * <code>signAttribute</code>. This is used * to map the <code>SIGN</code> attribute to the <code>EXPONENT</code> * attribute as necessary. * <p> * This is used by <code>subformat</code> to add the prefix/suffix. */ private void append(StringBuffer result, String string, FieldDelegate delegate, FieldPosition[] positions, Format.Field signAttribute) { int start = result.length(); if (string.length() > 0) { result.append(string); for (int counter = 0, max = positions.length; counter < max; counter++) { FieldPosition fp = positions[counter]; Format.Field attribute = fp.getFieldAttribute(); if (attribute == Field.SIGN) { attribute = signAttribute; } delegate.formatted(attribute, attribute, start + fp.getBeginIndex(), start + fp.getEndIndex(), result); } } } /** * Parses text from a string to produce a <code>Number</code>. * <p> * The method attempts to parse text starting at the index given by * <code>pos</code>. * If parsing succeeds, then the index of <code>pos</code> is updated * to the index after the last character used (parsing does not necessarily * use all characters up to the end of the string), and the parsed * number is returned. The updated <code>pos</code> can be used to * indicate the starting point for the next call to this method. * If an error occurs, then the index of <code>pos</code> is not * changed, the error index of <code>pos</code> is set to the index of * the character where the error occurred, and null is returned. * <p> * The most economical subclass that can represent the number given by the * string is chosen. Most integer values are returned as <code>Long</code> * objects, no matter how they are written: <code>"17"</code> and * <code>"17.000"</code> both parse to <code>Long(17)</code>. Values that * cannot fit into a <code>Long</code> are returned as * <code>Double</code>s. This includes values with a fractional part, * infinite values, <code>NaN</code>, and the value -0.0. * <code>DecimalFormat</code> does <em>not</em> decide whether to return * a <code>Double</code> or a <code>Long</code> based on the presence of a * decimal separator in the source string. Doing so would prevent integers * that overflow the mantissa of a double, such as * <code>"10,000,000,000,000,000.00"</code>, from being parsed accurately. * Currently, the only classes that <code>parse</code> returns are * <code>Long</code> and <code>Double</code>, but callers should not rely * on this. Callers may use the <code>Number</code> methods * <code>doubleValue</code>, <code>longValue</code>, etc., to obtain the * type they want. * <p> * <code>DecimalFormat</code> parses all Unicode characters that represent * decimal digits, as defined by <code>Character.digit()</code>. In * addition, <code>DecimalFormat</code> also recognizes as digits the ten * consecutive characters starting with the localized zero digit defined in * the <code>DecimalFormatSymbols</code> object. * * @param text the string to be parsed * @param pos A <code>ParsePosition</code> object with index and error * index information as described above. * @return the parsed value, or <code>null</code> if the parse fails * @exception NullPointerException if <code>text</code> or * <code>pos</code> is null. */ public Number parse(String text, ParsePosition pos) { // special case NaN if (text.regionMatches(pos.index, symbols.getNaN(), 0, symbols.getNaN().length())) { pos.index = pos.index + symbols.getNaN().length(); return new Double(Double.NaN); } boolean[] status = new boolean[STATUS_LENGTH]; if (!subparse(text, pos, digitList, false, status)) return null; double doubleResult = 0.0; long longResult = 0; boolean gotDouble = true; // Finally, have DigitList parse the digits into a value. if (status[STATUS_INFINITE]) { doubleResult = Double.POSITIVE_INFINITY; } else if (digitList.fitsIntoLong(status[STATUS_POSITIVE], isParseIntegerOnly())) { gotDouble = false; longResult = digitList.getLong(); } else doubleResult = digitList.getDouble(); // Divide by multiplier. We have to be careful here not to do unneeded // conversions between double and long. if (multiplier != 1) { if (gotDouble) doubleResult /= multiplier; else { // Avoid converting to double if we can if (longResult % multiplier == 0) { longResult /= multiplier; } else { doubleResult = ((double)longResult) / multiplier; if (doubleResult < 0) doubleResult = -doubleResult; gotDouble = true; } } } if (!status[STATUS_POSITIVE]) { doubleResult = -doubleResult; // If longResult was Long.MIN_VALUE or a divisor of it (if // multiplier != 1) then don't negate it. if (longResult > 0) { longResult = -longResult; } } // At this point, if we divided the result by the multiplier, the result may // fit into a long. We check for this case and return a long if possible. // We must do this AFTER applying the negative (if appropriate) in order to // handle the case of LONG_MIN; otherwise, if we do this with a positive value // -LONG_MIN, the double is > 0, but the long is < 0. This is a C++-specific // situation. We also must retain a double in the case of -0.0, which will // compare as == to a long 0 cast to a double (bug 4162852). if (multiplier != 1 && gotDouble) { longResult = (long)doubleResult; gotDouble = (doubleResult != (double)longResult) || (doubleResult == 0.0 && !status[STATUS_POSITIVE] && !isParseIntegerOnly()); } return gotDouble ? (Number)new Double(doubleResult) : (Number)new Long(longResult); } private static final int STATUS_INFINITE = 0; private static final int STATUS_POSITIVE = 1; private static final int STATUS_LENGTH = 2; /** * Parse the given text into a number. The text is parsed beginning at * parsePosition, until an unparseable character is seen. * @param text The string to parse. * @param parsePosition The position at which to being parsing. Upon * return, the first unparseable character. * @param digits The DigitList to set to the parsed value. * @param isExponent If true, parse an exponent. This means no * infinite values and integer only. * @param status Upon return contains boolean status flags indicating * whether the value was infinite and whether it was positive. */ private final boolean subparse(String text, ParsePosition parsePosition, DigitList digits, boolean isExponent, boolean status[]) { int position = parsePosition.index; int oldStart = parsePosition.index; int backup; // check for positivePrefix; take longest boolean gotPositive = text.regionMatches(position,positivePrefix,0, positivePrefix.length()); boolean gotNegative = text.regionMatches(position,negativePrefix,0, negativePrefix.length()); if (gotPositive && gotNegative) { if (positivePrefix.length() > negativePrefix.length()) gotNegative = false; else if (positivePrefix.length() < negativePrefix.length()) gotPositive = false; } if (gotPositive) { position += positivePrefix.length(); } else if (gotNegative) { position += negativePrefix.length(); } else { parsePosition.errorIndex = position; return false; } // process digits or Inf, find decimal position status[STATUS_INFINITE] = false; if (!isExponent && text.regionMatches(position,symbols.getInfinity(),0, symbols.getInfinity().length())) { position += symbols.getInfinity().length(); status[STATUS_INFINITE] = true; } else { // We now have a string of digits, possibly with grouping symbols, // and decimal points. We want to process these into a DigitList. // We don't want to put a bunch of leading zeros into the DigitList // though, so we keep track of the location of the decimal point, // put only significant digits into the DigitList, and adjust the // exponent as needed. digits.decimalAt = digits.count = 0; char zero = symbols.getZeroDigit(); char decimal = isCurrencyFormat ? symbols.getMonetaryDecimalSeparator() : symbols.getDecimalSeparator(); char grouping = symbols.getGroupingSeparator(); char exponentChar = symbols.getExponentialSymbol(); boolean sawDecimal = false; boolean sawExponent = false; boolean sawDigit = false; int exponent = 0; // Set to the exponent value, if any // We have to track digitCount ourselves, because digits.count will // pin when the maximum allowable digits is reached. int digitCount = 0; backup = -1; for (; position < text.length(); ++position) { char ch = text.charAt(position); /* We recognize all digit ranges, not only the Latin digit range * '0'..'9'. We do so by using the Character.digit() method, * which converts a valid Unicode digit to the range 0..9. * * The character 'ch' may be a digit. If so, place its value * from 0 to 9 in 'digit'. First try using the locale digit, * which may or MAY NOT be a standard Unicode digit range. If * this fails, try using the standard Unicode digit ranges by * calling Character.digit(). If this also fails, digit will * have a value outside the range 0..9. */ int digit = ch - zero; if (digit < 0 || digit > 9) digit = Character.digit(ch, 10); if (digit == 0) { // Cancel out backup setting (see grouping handler below) backup = -1; // Do this BEFORE continue statement below!!! sawDigit = true; // Handle leading zeros if (digits.count == 0) { // Ignore leading zeros in integer part of number. if (!sawDecimal) continue; // If we have seen the decimal, but no significant digits yet, // then we account for leading zeros by decrementing the // digits.decimalAt into negative values. --digits.decimalAt; } else { ++digitCount; digits.append((char)(digit + '0')); } } else if (digit > 0 && digit <= 9) // [sic] digit==0 handled above { sawDigit = true; ++digitCount; digits.append((char)(digit + '0')); // Cancel out backup setting (see grouping handler below) backup = -1; } else if (!isExponent && ch == decimal) { // If we're only parsing integers, or if we ALREADY saw the // decimal, then don't parse this one. if (isParseIntegerOnly() || sawDecimal) break; digits.decimalAt = digitCount; // Not digits.count! sawDecimal = true; } else if (!isExponent && ch == grouping && isGroupingUsed()) { if (sawDecimal) { break; } // Ignore grouping characters, if we are using them, but require // that they be followed by a digit. Otherwise we backup and // reprocess them. backup = position; } else if (!isExponent && ch == exponentChar && !sawExponent) { // Process the exponent by recursively calling this method. ParsePosition pos = new ParsePosition(position + 1); boolean[] stat = new boolean[STATUS_LENGTH]; DigitList exponentDigits = new DigitList();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -