X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/0f5d89e82340278ed3d7d50029f37cab2c41a57e..c5116b9f5a666b9d59f443b3770acd6ef64dc6c3:/icuSources/i18n/number_patternstring.cpp diff --git a/icuSources/i18n/number_patternstring.cpp b/icuSources/i18n/number_patternstring.cpp index 63195eed..c7201a69 100644 --- a/icuSources/i18n/number_patternstring.cpp +++ b/icuSources/i18n/number_patternstring.cpp @@ -15,6 +15,7 @@ #include "unicode/utf16.h" #include "number_utils.h" #include "number_roundingutils.h" +#include "number_mapper.h" using namespace icu; using namespace icu::number; @@ -49,7 +50,7 @@ PatternParser::parseToExistingProperties(const UnicodeString& pattern, DecimalFo char16_t ParsedPatternInfo::charAt(int32_t flags, int32_t index) const { const Endpoints& endpoints = getEndpoints(flags); if (index < 0 || index >= endpoints.end - endpoints.start) { - U_ASSERT(false); + UPRV_UNREACHABLE; } return pattern.charAt(endpoints.start + index); } @@ -468,7 +469,15 @@ void PatternParser::parseToExistingPropertiesImpl(const UnicodeString& pattern, } ParsedPatternInfo patternInfo; - parseToPatternInfo(pattern, patternInfo, status); + if (pattern.compare(u"#.##E+00;-#.##E+00",18)==0) { + // Special hack for Numbers; if applying the Numbers-style scientific pattern, + // then replace it with the pattern beginning with 0 that would have resulted + // in older versions of ICU such as ICU 61. rdar://51601250 + UnicodeString newPattern(TRUE,u"0.##E+00",8); + parseToPatternInfo(newPattern, patternInfo, status); + } else { + parseToPatternInfo(pattern, patternInfo, status); + } if (U_FAILURE(status)) { return; } patternInfoToProperties(properties, patternInfo, ignoreRounding, status); } @@ -643,69 +652,74 @@ PatternParser::patternInfoToProperties(DecimalFormatProperties& properties, Pars /// End PatternStringParser.java; begin PatternStringUtils.java /// /////////////////////////////////////////////////////////////////// +// Determine whether a given roundingIncrement should be ignored for formatting +// based on the current maxFrac value (maximum fraction digits). For example a +// roundingIncrement of 0.01 should be ignored if maxFrac is 1, but not if maxFrac +// is 2 or more. Note that roundingIncrements are rounded in significance, so +// a roundingIncrement of 0.006 is treated like 0.01 for this determination, i.e. +// it should not be ignored if maxFrac is 2 or more (but a roundingIncrement of +// 0.005 is treated like 0.001 for significance). This is the reason for the +// initial doubling below. +// roundIncr must be non-zero. +// Apple enhancement per rdar://51452216: Takes pointer to roundIncr; if function +// returns false, roundIncr will be rounded as necessary given maxFrac value. +bool PatternStringUtils::ignoreRoundingIncrement(double* roundIncrPtr, int32_t maxFrac) { + if (maxFrac < 0) { + return false; + } + int32_t frac = 0; + double denom = 20.0; + double roundIncr = *roundIncrPtr * 2.0; + for (frac = 0; frac <= maxFrac && roundIncr <= 1.0; frac++, roundIncr *= 10.0, denom *= 10.0); + if (frac <= maxFrac) { + *roundIncrPtr = (double)((int)(roundIncr*10.0))/denom; + return false; + } + return true; +} + UnicodeString PatternStringUtils::propertiesToPatternString(const DecimalFormatProperties& properties, UErrorCode& status) { UnicodeString sb; // Convenience references // The uprv_min() calls prevent DoS - int dosMax = 100; - int groupingSize = uprv_min(properties.secondaryGroupingSize, dosMax); - int firstGroupingSize = uprv_min(properties.groupingSize, dosMax); - int paddingWidth = uprv_min(properties.formatWidth, dosMax); + int32_t dosMax = 100; + int32_t grouping1 = uprv_max(0, uprv_min(properties.groupingSize, dosMax)); + int32_t grouping2 = uprv_max(0, uprv_min(properties.secondaryGroupingSize, dosMax)); + bool useGrouping = properties.groupingUsed; + int32_t paddingWidth = uprv_min(properties.formatWidth, dosMax); NullableValue paddingLocation = properties.padPosition; UnicodeString paddingString = properties.padString; - int minInt = uprv_max(uprv_min(properties.minimumIntegerDigits, dosMax), 0); - int maxInt = uprv_min(properties.maximumIntegerDigits, dosMax); - int minFrac = uprv_max(uprv_min(properties.minimumFractionDigits, dosMax), 0); - int maxFrac = uprv_min(properties.maximumFractionDigits, dosMax); - int minSig = uprv_min(properties.minimumSignificantDigits, dosMax); - int maxSig = uprv_min(properties.maximumSignificantDigits, dosMax); + int32_t minInt = uprv_max(0, uprv_min(properties.minimumIntegerDigits, dosMax)); + int32_t maxInt = uprv_min(properties.maximumIntegerDigits, dosMax); + int32_t minFrac = uprv_max(0, uprv_min(properties.minimumFractionDigits, dosMax)); + int32_t maxFrac = uprv_min(properties.maximumFractionDigits, dosMax); + int32_t minSig = uprv_min(properties.minimumSignificantDigits, dosMax); + int32_t maxSig = uprv_min(properties.maximumSignificantDigits, dosMax); bool alwaysShowDecimal = properties.decimalSeparatorAlwaysShown; - int exponentDigits = uprv_min(properties.minimumExponentDigits, dosMax); + int32_t exponentDigits = uprv_min(properties.minimumExponentDigits, dosMax); bool exponentShowPlusSign = properties.exponentSignAlwaysShown; - UnicodeString pp = properties.positivePrefix; - UnicodeString ppp = properties.positivePrefixPattern; - UnicodeString ps = properties.positiveSuffix; - UnicodeString psp = properties.positiveSuffixPattern; - UnicodeString np = properties.negativePrefix; - UnicodeString npp = properties.negativePrefixPattern; - UnicodeString ns = properties.negativeSuffix; - UnicodeString nsp = properties.negativeSuffixPattern; + + PropertiesAffixPatternProvider affixes(properties, status); // Prefixes - if (!ppp.isBogus()) { - sb.append(ppp); - } - sb.append(AffixUtils::escape(pp)); - int afterPrefixPos = sb.length(); + sb.append(affixes.getString(AffixPatternProvider::AFFIX_POS_PREFIX)); + int32_t afterPrefixPos = sb.length(); // Figure out the grouping sizes. - int grouping1, grouping2, grouping; - if (groupingSize != uprv_min(dosMax, -1) && firstGroupingSize != uprv_min(dosMax, -1) && - groupingSize != firstGroupingSize) { - grouping = groupingSize; - grouping1 = groupingSize; - grouping2 = firstGroupingSize; - } else if (groupingSize != uprv_min(dosMax, -1)) { - grouping = groupingSize; - grouping1 = 0; - grouping2 = groupingSize; - } else if (firstGroupingSize != uprv_min(dosMax, -1)) { - grouping = groupingSize; - grouping1 = 0; - grouping2 = firstGroupingSize; - } else { - grouping = 0; + if (!useGrouping) { grouping1 = 0; grouping2 = 0; + } else if (grouping1 == grouping2) { + grouping1 = 0; } - int groupingLength = grouping1 + grouping2 + 1; + int32_t groupingLength = grouping1 + grouping2 + 1; // Figure out the digits we need to put in the pattern. double roundingInterval = properties.roundingIncrement; UnicodeString digitsString; - int digitsStringScale = 0; + int32_t digitsStringScale = 0; if (maxSig != uprv_min(dosMax, -1)) { // Significant Digits. while (digitsString.length() < minSig) { @@ -714,9 +728,9 @@ UnicodeString PatternStringUtils::propertiesToPatternString(const DecimalFormatP while (digitsString.length() < maxSig) { digitsString.append(u'#'); } - } else if (roundingInterval != 0.0) { + } else if (roundingInterval != 0.0 && !ignoreRoundingIncrement(&roundingInterval,maxFrac)) { // Rounding Interval. - digitsStringScale = -roundingutils::doubleFractionLength(roundingInterval); + digitsStringScale = -roundingutils::doubleFractionLength(roundingInterval, nullptr); // TODO: Check for DoS here? DecimalQuantity incrementQuantity; incrementQuantity.setToDouble(roundingInterval); @@ -739,22 +753,30 @@ UnicodeString PatternStringUtils::propertiesToPatternString(const DecimalFormatP } // Write the digits to the string builder - int m0 = uprv_max(groupingLength, digitsString.length() + digitsStringScale); + int32_t m0 = uprv_max(groupingLength, digitsString.length() + digitsStringScale); m0 = (maxInt != dosMax) ? uprv_max(maxInt, m0) - 1 : m0 - 1; - int mN = (maxFrac != dosMax) ? uprv_min(-maxFrac, digitsStringScale) : digitsStringScale; - for (int magnitude = m0; magnitude >= mN; magnitude--) { - int di = digitsString.length() + digitsStringScale - magnitude - 1; + int32_t mN = (maxFrac != dosMax) ? uprv_min(-maxFrac, digitsStringScale) : digitsStringScale; + for (int32_t magnitude = m0; magnitude >= mN; magnitude--) { + int32_t di = digitsString.length() + digitsStringScale - magnitude - 1; if (di < 0 || di >= digitsString.length()) { sb.append(u'#'); } else { sb.append(digitsString.charAt(di)); } - if (magnitude > grouping2 && grouping > 0 && (magnitude - grouping2) % grouping == 0) { + // Decimal separator + if (magnitude == 0 && (alwaysShowDecimal || mN < 0)) { + sb.append(u'.'); + } + if (!useGrouping) { + continue; + } + // Least-significant grouping separator + if (magnitude > 0 && magnitude == grouping1) { sb.append(u','); - } else if (magnitude > 0 && magnitude == grouping2) { + } + // All other grouping separators + if (magnitude > grouping1 && grouping2 > 0 && (magnitude - grouping1) % grouping2 == 0) { sb.append(u','); - } else if (magnitude == 0 && (alwaysShowDecimal || mN < 0)) { - sb.append(u'.'); } } @@ -764,25 +786,22 @@ UnicodeString PatternStringUtils::propertiesToPatternString(const DecimalFormatP if (exponentShowPlusSign) { sb.append(u'+'); } - for (int i = 0; i < exponentDigits; i++) { + for (int32_t i = 0; i < exponentDigits; i++) { sb.append(u'0'); } } // Suffixes - int beforeSuffixPos = sb.length(); - if (!psp.isBogus()) { - sb.append(psp); - } - sb.append(AffixUtils::escape(ps)); + int32_t beforeSuffixPos = sb.length(); + sb.append(affixes.getString(AffixPatternProvider::AFFIX_POS_SUFFIX)); // Resolve Padding - if (paddingWidth != -1 && !paddingLocation.isNull()) { + if (paddingWidth > 0 && !paddingLocation.isNull()) { while (paddingWidth - sb.length() > 0) { sb.insert(afterPrefixPos, u'#'); beforeSuffixPos++; } - int addedLength; + int32_t addedLength; switch (paddingLocation.get(status)) { case PadPosition::UNUM_PAD_BEFORE_PREFIX: addedLength = escapePaddingString(paddingString, sb, 0, status); @@ -810,23 +829,16 @@ UnicodeString PatternStringUtils::propertiesToPatternString(const DecimalFormatP // Negative affixes // Ignore if the negative prefix pattern is "-" and the negative suffix is empty - if (!np.isBogus() || !ns.isBogus() || (npp.isBogus() && !nsp.isBogus()) || - (!npp.isBogus() && (npp.length() != 1 || npp.charAt(0) != u'-' || nsp.length() != 0))) { + if (affixes.hasNegativeSubpattern()) { sb.append(u';'); - if (!npp.isBogus()) { - sb.append(npp); - } - sb.append(AffixUtils::escape(np)); + sb.append(affixes.getString(AffixPatternProvider::AFFIX_NEG_PREFIX)); // Copy the positive digit format into the negative. // This is optional; the pattern is the same as if '#' were appended here instead. // NOTE: It is not safe to append the UnicodeString to itself, so we need to copy. // See http://bugs.icu-project.org/trac/ticket/13707 UnicodeString copy(sb); sb.append(copy, afterPrefixPos, beforeSuffixPos - afterPrefixPos); - if (!nsp.isBogus()) { - sb.append(nsp); - } - sb.append(AffixUtils::escape(ns)); + sb.append(affixes.getString(AffixPatternProvider::AFFIX_NEG_SUFFIX)); } return sb;