]> granicus.if.org Git - icu/commitdiff
ICU-20230 Implementing COMPACT field.
authorShane Carr <shane@unicode.org>
Fri, 16 Nov 2018 04:58:24 +0000 (20:58 -0800)
committerShane F. Carr <shane@unicode.org>
Mon, 19 Nov 2018 23:21:36 +0000 (16:21 -0700)
Adds some plumbing to allow MutablePatternModifier to set fields, and otherwise builds upon the infrastructure from the previous commit to add the MEASURE_UNIT field.

19 files changed:
icu4c/source/i18n/number_affixutils.cpp
icu4c/source/i18n/number_affixutils.h
icu4c/source/i18n/number_compact.cpp
icu4c/source/i18n/number_formatimpl.cpp
icu4c/source/i18n/number_patternmodifier.cpp
icu4c/source/i18n/number_patternmodifier.h
icu4c/source/i18n/unicode/numfmt.h
icu4c/source/i18n/unicode/unum.h
icu4c/source/test/intltest/numbertest_affixutils.cpp
icu4c/source/test/intltest/numbertest_api.cpp
icu4c/source/test/intltest/numbertest_patternmodifier.cpp
icu4j/main/classes/core/src/com/ibm/icu/impl/number/AffixUtils.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/MutablePatternModifier.java
icu4j/main/classes/core/src/com/ibm/icu/number/CompactNotation.java
icu4j/main/classes/core/src/com/ibm/icu/number/NumberFormatterImpl.java
icu4j/main/classes/core/src/com/ibm/icu/text/NumberFormat.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/AffixUtilsTest.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/MutablePatternModifierTest.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberFormatterApiTest.java

index 8da29a03d52d56c1512236aed1ceb260a2c36bea..0da353bb7c1aa8bc02ac9e6ac180791ab3e6d5b4 100644 (file)
@@ -158,7 +158,7 @@ Field AffixUtils::getFieldForType(AffixPatternType type) {
 
 int32_t
 AffixUtils::unescape(const UnicodeString &affixPattern, NumberStringBuilder &output, int32_t position,
-                     const SymbolProvider &provider, UErrorCode &status) {
+                     const SymbolProvider &provider, Field field, UErrorCode &status) {
     int32_t length = 0;
     AffixTag tag;
     while (hasNext(tag, affixPattern)) {
@@ -171,7 +171,7 @@ AffixUtils::unescape(const UnicodeString &affixPattern, NumberStringBuilder &out
             length += output.insert(
                     position + length, provider.getSymbol(tag.type), getFieldForType(tag.type), status);
         } else {
-            length += output.insertCodePoint(position + length, tag.codePoint, UNUM_FIELD_COUNT, status);
+            length += output.insertCodePoint(position + length, tag.codePoint, field, status);
         }
     }
     return length;
index 1d7e1a115e046a036aede4e810de2391185eebcd..f011a54b316166879d818c5b65c9d8e7787dcbfd 100644 (file)
@@ -144,7 +144,8 @@ class U_I18N_API AffixUtils {
      * @param provider An object to generate locale symbols.
      */
     static int32_t unescape(const UnicodeString& affixPattern, NumberStringBuilder& output,
-                            int32_t position, const SymbolProvider& provider, UErrorCode& status);
+                            int32_t position, const SymbolProvider& provider, Field field,
+                            UErrorCode& status);
 
     /**
    * Sames as {@link #unescape}, but only calculates the code point count.  More efficient than {@link #unescape}
index 10942c35f535df6bc8bd76b1e0212064fd43a869..cbcfb679ebf17f757fb84e33741b0e055302ac18 100644 (file)
@@ -260,7 +260,7 @@ void CompactHandler::precomputeAllModifiers(MutablePatternModifier &buildReferen
         ParsedPatternInfo patternInfo;
         PatternParser::parseToPatternInfo(UnicodeString(patternString), patternInfo, status);
         if (U_FAILURE(status)) { return; }
-        buildReference.setPatternInfo(&patternInfo);
+        buildReference.setPatternInfo(&patternInfo, UNUM_COMPACT_FIELD);
         info.mod = buildReference.createImmutable(status);
         if (U_FAILURE(status)) { return; }
         info.patternString = patternString;
@@ -310,7 +310,7 @@ void CompactHandler::processQuantity(DecimalQuantity &quantity, MicroProps &micr
         ParsedPatternInfo &patternInfo = const_cast<CompactHandler *>(this)->unsafePatternInfo;
         PatternParser::parseToPatternInfo(UnicodeString(patternString), patternInfo, status);
         static_cast<MutablePatternModifier*>(const_cast<Modifier*>(micros.modMiddle))
-            ->setPatternInfo(&patternInfo);
+            ->setPatternInfo(&patternInfo, UNUM_COMPACT_FIELD);
     }
 
     // We already performed rounding. Do not perform it again.
index 60c18ee284e238176593207bacd824b34fec392b..c64703699cd4b9d8503fc5871272fb296d656c2f 100644 (file)
@@ -344,7 +344,8 @@ NumberFormatterImpl::macrosToMicroGenerator(const MacroProps& macros, bool safe,
     fPatternModifier.adoptInstead(patternModifier);
     patternModifier->setPatternInfo(
             macros.affixProvider != nullptr ? macros.affixProvider
-                                            : static_cast<const AffixPatternProvider*>(fPatternInfo.getAlias()));
+                                            : static_cast<const AffixPatternProvider*>(fPatternInfo.getAlias()),
+            UNUM_FIELD_COUNT);
     patternModifier->setPatternAttributes(fMicros.sign, isPermille);
     if (patternModifier->needsPlurals()) {
         patternModifier->setSymbols(
index 4c61a0d35bca828b3dcf9adc3e17970338b9f0f1..0146ee99056d55fe027608f2231ef7bd16598a6b 100644 (file)
@@ -23,13 +23,14 @@ AffixPatternProvider::~AffixPatternProvider() = default;
 MutablePatternModifier::MutablePatternModifier(bool isStrong)
         : fStrong(isStrong) {}
 
-void MutablePatternModifier::setPatternInfo(const AffixPatternProvider* patternInfo) {
+void MutablePatternModifier::setPatternInfo(const AffixPatternProvider* patternInfo, Field field) {
     fPatternInfo = patternInfo;
+    fField = field;
 }
 
 void MutablePatternModifier::setPatternAttributes(UNumberSignDisplay signDisplay, bool perMille) {
     fSignDisplay = signDisplay;
-    this->perMilleReplacesPercent = perMille;
+    fPerMilleReplacesPercent = perMille;
 }
 
 void MutablePatternModifier::setSymbols(const DecimalFormatSymbols* symbols,
@@ -255,20 +256,20 @@ bool MutablePatternModifier::semanticallyEquivalent(const Modifier& other) const
 
 int32_t MutablePatternModifier::insertPrefix(NumberStringBuilder& sb, int position, UErrorCode& status) {
     prepareAffix(true);
-    int length = AffixUtils::unescape(currentAffix, sb, position, *this, status);
+    int32_t length = AffixUtils::unescape(currentAffix, sb, position, *this, fField, status);
     return length;
 }
 
 int32_t MutablePatternModifier::insertSuffix(NumberStringBuilder& sb, int position, UErrorCode& status) {
     prepareAffix(false);
-    int length = AffixUtils::unescape(currentAffix, sb, position, *this, status);
+    int32_t length = AffixUtils::unescape(currentAffix, sb, position, *this, fField, status);
     return length;
 }
 
 /** This method contains the heart of the logic for rendering LDML affix strings. */
 void MutablePatternModifier::prepareAffix(bool isPrefix) {
     PatternStringUtils::patternInfoToStringBuilder(
-            *fPatternInfo, isPrefix, fSignum, fSignDisplay, fPlural, perMilleReplacesPercent, currentAffix);
+            *fPatternInfo, isPrefix, fSignum, fSignDisplay, fPlural, fPerMilleReplacesPercent, currentAffix);
 }
 
 UnicodeString MutablePatternModifier::getSymbol(AffixPatternType type) const {
index ea80d6305e75b4444934f13733f91c27e9a79c75..9e6e33fccae0d30d2365f8c8be39f60c0faf70f6 100644 (file)
@@ -95,8 +95,11 @@ class U_I18N_API MutablePatternModifier
      * Sets a reference to the parsed decimal format pattern, usually obtained from
      * {@link PatternStringParser#parseToPatternInfo(String)}, but any implementation of {@link AffixPatternProvider} is
      * accepted.
+     *
+     * @param field
+     *            Which field to use for literal characters in the pattern.
      */
-    void setPatternInfo(const AffixPatternProvider *patternInfo);
+    void setPatternInfo(const AffixPatternProvider *patternInfo, Field field);
 
     /**
      * Sets attributes that imply changes to the literal interpretation of the pattern string affixes.
@@ -203,8 +206,9 @@ class U_I18N_API MutablePatternModifier
 
     // Pattern details (initialized in setPatternInfo and setPatternAttributes)
     const AffixPatternProvider *fPatternInfo;
+    Field fField;
     UNumberSignDisplay fSignDisplay;
-    bool perMilleReplacesPercent;
+    bool fPerMilleReplacesPercent;
 
     // Symbol details (initialized in setSymbols)
     const DecimalFormatSymbols *fSymbols;
index 30979b61e35ebd13fa8e0933a8c1d97897c7c976..af124c6e6be941531867c769284d9cfb6172df05 100644 (file)
@@ -239,6 +239,8 @@ public:
         kSignField = UNUM_SIGN_FIELD,
         /** @draft ICU 64 */
         kMeasureUnitField = UNUM_MEASURE_UNIT_FIELD,
+        /** @draft ICU 64 */
+        kCompactField = UNUM_COMPACT_FIELD,
 
     /**
      * These constants are provided for backwards compatibility only.
index 3f07f9459eb745598af2b94defaf441f23f6d405..cdc6d056bc280dd582e2fde63e9da52936caaffa 100644 (file)
@@ -377,6 +377,9 @@ typedef enum UNumberFormatFields {
     UNUM_SIGN_FIELD,
     /** @draft ICU 64 */
     UNUM_MEASURE_UNIT_FIELD,
+    /** @draft ICU 64 */
+    UNUM_COMPACT_FIELD,
+
 #ifndef U_HIDE_DEPRECATED_API
     /**
      * One more than the highest normal UNumberFormatFields value.
index d72991a042fc447f71c1b0f3442229a2ff393c4b..f2029667e129a805fc84ff522122d39a31ef98d7 100644 (file)
@@ -223,7 +223,7 @@ void AffixUtilsTest::testUnescapeWithSymbolProvider() {
         UnicodeString input(cas[0]);
         UnicodeString expected(cas[1]);
         sb.clear();
-        AffixUtils::unescape(input, sb, 0, provider, status);
+        AffixUtils::unescape(input, sb, 0, provider, UNUM_FIELD_COUNT, status);
         assertSuccess("Spot 1", status);
         assertEquals(input, expected, sb.toUnicodeString());
         assertEquals(input, expected, sb.toTempUnicodeString());
@@ -233,7 +233,7 @@ void AffixUtilsTest::testUnescapeWithSymbolProvider() {
     sb.clear();
     sb.append(u"abcdefg", UNUM_FIELD_COUNT, status);
     assertSuccess("Spot 2", status);
-    AffixUtils::unescape(u"-+%", sb, 4, provider, status);
+    AffixUtils::unescape(u"-+%", sb, 4, provider, UNUM_FIELD_COUNT, status);
     assertSuccess("Spot 3", status);
     assertEquals(u"Symbol provider into middle", u"abcd123efg", sb.toUnicodeString());
 }
@@ -241,7 +241,7 @@ void AffixUtilsTest::testUnescapeWithSymbolProvider() {
 UnicodeString AffixUtilsTest::unescapeWithDefaults(const SymbolProvider &defaultProvider,
                                                           UnicodeString input, UErrorCode &status) {
     NumberStringBuilder nsb;
-    int32_t length = AffixUtils::unescape(input, nsb, 0, defaultProvider, status);
+    int32_t length = AffixUtils::unescape(input, nsb, 0, defaultProvider, UNUM_FIELD_COUNT, status);
     assertEquals("Return value of unescape", nsb.length(), length);
     return nsb.toUnicodeString();
 }
index c7d59accc13b75c9e09f6e006c8331f2d7184575..0ae6d83a057de499d09fe9f8ef07268bf71005db 100644 (file)
@@ -2349,6 +2349,130 @@ void NumberFormatterApiTest::fieldPositionCoverage() {
                 expectedFieldPositions,
                 sizeof(expectedFieldPositions)/sizeof(*expectedFieldPositions));
     }
+
+    {
+        const char16_t* message = u"Compact field basic";
+        FormattedNumber result = assertFormatSingle(
+                message,
+                u"compact-short",
+                NumberFormatter::with().notation(Notation::compactShort()),
+                Locale::getUS(),
+                65000,
+                u"65K");
+        static const UFieldPosition expectedFieldPositions[] = {
+                // field, begin index, end index
+                {UNUM_INTEGER_FIELD, 0, 2},
+                {UNUM_COMPACT_FIELD, 2, 3}};
+        assertFieldPositions(
+                message,
+                result,
+                expectedFieldPositions,
+                sizeof(expectedFieldPositions)/sizeof(*expectedFieldPositions));
+    }
+
+    {
+        const char16_t* message = u"Compact field with spaces";
+        FormattedNumber result = assertFormatSingle(
+                message,
+                u"compact-long",
+                NumberFormatter::with().notation(Notation::compactLong()),
+                Locale::getUS(),
+                65000,
+                u"65 thousand");
+        static const UFieldPosition expectedFieldPositions[] = {
+                // field, begin index, end index
+                {UNUM_INTEGER_FIELD, 0, 2},
+                {UNUM_COMPACT_FIELD, 3, 11}};
+        assertFieldPositions(
+                message,
+                result,
+                expectedFieldPositions,
+                sizeof(expectedFieldPositions)/sizeof(*expectedFieldPositions));
+    }
+
+    {
+        const char16_t* message = u"Compact field with inner space";
+        FormattedNumber result = assertFormatSingle(
+                message,
+                u"compact-long",
+                NumberFormatter::with().notation(Notation::compactLong()),
+                "fil",  // locale with interesting data
+                6000,
+                u"6 na libo");
+        static const UFieldPosition expectedFieldPositions[] = {
+                // field, begin index, end index
+                {UNUM_INTEGER_FIELD, 0, 1},
+                {UNUM_COMPACT_FIELD, 2, 9}};
+        assertFieldPositions(
+                message,
+                result,
+                expectedFieldPositions,
+                sizeof(expectedFieldPositions)/sizeof(*expectedFieldPositions));
+    }
+
+    {
+        const char16_t* message = u"Compact field with bidi mark";
+        FormattedNumber result = assertFormatSingle(
+                message,
+                u"compact-long",
+                NumberFormatter::with().notation(Notation::compactLong()),
+                "he",  // locale with interesting data
+                6000,
+                u"\u200F6 אלף");
+        static const UFieldPosition expectedFieldPositions[] = {
+                // field, begin index, end index
+                {UNUM_INTEGER_FIELD, 1, 2},
+                {UNUM_COMPACT_FIELD, 3, 6}};
+        assertFieldPositions(
+                message,
+                result,
+                expectedFieldPositions,
+                sizeof(expectedFieldPositions)/sizeof(*expectedFieldPositions));
+    }
+
+    {
+        const char16_t* message = u"Compact with currency fields";
+        FormattedNumber result = assertFormatSingle(
+                message,
+                u"compact-short currency/USD",
+                NumberFormatter::with().notation(Notation::compactShort()).unit(USD),
+                "sr_Latn",  // locale with interesting data
+                65000,
+                u"65 hilj. US$");
+        static const UFieldPosition expectedFieldPositions[] = {
+                // field, begin index, end index
+                {UNUM_INTEGER_FIELD, 0, 2},
+                {UNUM_COMPACT_FIELD, 3, 8},
+                {UNUM_CURRENCY_FIELD, 9, 12}};
+        assertFieldPositions(
+                message,
+                result,
+                expectedFieldPositions,
+                sizeof(expectedFieldPositions)/sizeof(*expectedFieldPositions));
+    }
+
+    {
+        const char16_t* message = u"Compact with measure unit fields";
+        FormattedNumber result = assertFormatSingle(
+                message,
+                u"compact-long measure-unit/length-meter unit-width-full-name",
+                NumberFormatter::with().notation(Notation::compactLong())
+                    .unit(METER)
+                    .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
+                Locale::getUS(),
+                65000,
+                u"65 thousand meters");
+        static const UFieldPosition expectedFieldPositions[] = {
+                // field, begin index, end index
+                {UNUM_INTEGER_FIELD, 0, 2},
+                {UNUM_COMPACT_FIELD, 3, 11},
+                {UNUM_MEASURE_UNIT_FIELD, 12, 18}};
+        assertFieldPositions(
+                message,
+                result,
+                expectedFieldPositions,
+                sizeof(expectedFieldPositions)/sizeof(*expectedFieldPositions));
+    }
 }
 
 void NumberFormatterApiTest::toFormat() {
index 3a0fda8267536b34aeb122b6d2b2846db2fb1687..2156c9b435eecd25f644021f20d8b39262107480 100644 (file)
@@ -26,7 +26,7 @@ void PatternModifierTest::testBasic() {
     ParsedPatternInfo patternInfo;
     PatternParser::parseToPatternInfo(u"a0b", patternInfo, status);
     assertSuccess("Spot 1", status);
-    mod.setPatternInfo(&patternInfo);
+    mod.setPatternInfo(&patternInfo, UNUM_FIELD_COUNT);
     mod.setPatternAttributes(UNUM_SIGN_AUTO, false);
     DecimalFormatSymbols symbols(Locale::getEnglish(), status);
     CurrencySymbols currencySymbols({u"USD", status}, "en", status);
@@ -58,7 +58,7 @@ void PatternModifierTest::testBasic() {
     ParsedPatternInfo patternInfo2;
     PatternParser::parseToPatternInfo(u"a0b;c-0d", patternInfo2, status);
     assertSuccess("Spot 4", status);
-    mod.setPatternInfo(&patternInfo2);
+    mod.setPatternInfo(&patternInfo2, UNUM_FIELD_COUNT);
     mod.setPatternAttributes(UNUM_SIGN_AUTO, false);
     mod.setNumberProperties(1, StandardPlural::Form::COUNT);
     assertEquals("Pattern a0b;c-0d", u"a", getPrefix(mod, status));
@@ -88,7 +88,7 @@ void PatternModifierTest::testPatternWithNoPlaceholder() {
     ParsedPatternInfo patternInfo;
     PatternParser::parseToPatternInfo(u"abc", patternInfo, status);
     assertSuccess("Spot 1", status);
-    mod.setPatternInfo(&patternInfo);
+    mod.setPatternInfo(&patternInfo, UNUM_FIELD_COUNT);
     mod.setPatternAttributes(UNUM_SIGN_AUTO, false);
     DecimalFormatSymbols symbols(Locale::getEnglish(), status);
     CurrencySymbols currencySymbols({u"USD", status}, "en", status);
@@ -131,7 +131,7 @@ void PatternModifierTest::testMutableEqualsImmutable() {
     ParsedPatternInfo patternInfo;
     PatternParser::parseToPatternInfo("a0b;c-0d", patternInfo, status);
     assertSuccess("Spot 1", status);
-    mod.setPatternInfo(&patternInfo);
+    mod.setPatternInfo(&patternInfo, UNUM_FIELD_COUNT);
     mod.setPatternAttributes(UNUM_SIGN_AUTO, false);
     DecimalFormatSymbols symbols(Locale::getEnglish(), status);
     CurrencySymbols currencySymbols({u"USD", status}, "en", status);
index 746cbd0a73528245857eb350cf3b47e3adb82d19..efb41bce61af112645b1104a4dc2e2f1491a3d5f 100644 (file)
@@ -309,7 +309,8 @@ public class AffixUtils {
             CharSequence affixPattern,
             NumberStringBuilder output,
             int position,
-            SymbolProvider provider) {
+            SymbolProvider provider,
+            NumberFormat.Field field) {
         assert affixPattern != null;
         int length = 0;
         long tag = 0L;
@@ -324,7 +325,7 @@ public class AffixUtils {
                         provider.getSymbol(typeOrCp),
                         getFieldForType(typeOrCp));
             } else {
-                length += output.insertCodePoint(position + length, typeOrCp, null);
+                length += output.insertCodePoint(position + length, typeOrCp, field);
             }
         }
         return length;
index a651b3907d92a1aadf54d64132e804002fc2cd28..d8875610bf850cbe613eb77ba30031f72b293596 100644 (file)
@@ -38,6 +38,7 @@ public class MutablePatternModifier implements Modifier, SymbolProvider, MicroPr
 
     // Pattern details
     AffixPatternProvider patternInfo;
+    Field field;
     SignDisplay signDisplay;
     boolean perMilleReplacesPercent;
 
@@ -71,9 +72,13 @@ public class MutablePatternModifier implements Modifier, SymbolProvider, MicroPr
      * Sets a reference to the parsed decimal format pattern, usually obtained from
      * {@link PatternStringParser#parseToPatternInfo(String)}, but any implementation of
      * {@link AffixPatternProvider} is accepted.
+     *
+     * @param field
+     *            Which field to use for literal characters in the pattern.
      */
-    public void setPatternInfo(AffixPatternProvider patternInfo) {
+    public void setPatternInfo(AffixPatternProvider patternInfo, Field field) {
         this.patternInfo = patternInfo;
+        this.field = field;
     }
 
     /**
@@ -343,13 +348,13 @@ public class MutablePatternModifier implements Modifier, SymbolProvider, MicroPr
 
     private int insertPrefix(NumberStringBuilder sb, int position) {
         prepareAffix(true);
-        int length = AffixUtils.unescape(currentAffix, sb, position, this);
+        int length = AffixUtils.unescape(currentAffix, sb, position, this, field);
         return length;
     }
 
     private int insertSuffix(NumberStringBuilder sb, int position) {
         prepareAffix(false);
-        int length = AffixUtils.unescape(currentAffix, sb, position, this);
+        int length = AffixUtils.unescape(currentAffix, sb, position, this, field);
         return length;
     }
 
index 31d1a8404fc29d23bdec602bfd9c64037c4f49c7..04e0eb9ea909c211620a186d3c09862a192fb835 100644 (file)
@@ -19,6 +19,7 @@ import com.ibm.icu.impl.number.MutablePatternModifier.ImmutablePatternModifier;
 import com.ibm.icu.impl.number.PatternStringParser;
 import com.ibm.icu.impl.number.PatternStringParser.ParsedPatternInfo;
 import com.ibm.icu.text.CompactDecimalFormat.CompactStyle;
+import com.ibm.icu.text.NumberFormat;
 import com.ibm.icu.text.PluralRules;
 import com.ibm.icu.util.ULocale;
 
@@ -96,7 +97,7 @@ public class CompactNotation extends Notation {
             }
             if (buildReference != null) {
                 // Safe code path
-                precomputedMods = new HashMap<String, ImmutablePatternModifier>();
+                precomputedMods = new HashMap<>();
                 precomputeAllModifiers(buildReference);
             } else {
                 // Unsafe code path
@@ -106,12 +107,12 @@ public class CompactNotation extends Notation {
 
         /** Used by the safe code path */
         private void precomputeAllModifiers(MutablePatternModifier buildReference) {
-            Set<String> allPatterns = new HashSet<String>();
+            Set<String> allPatterns = new HashSet<>();
             data.getUniquePatterns(allPatterns);
 
             for (String patternString : allPatterns) {
                 ParsedPatternInfo patternInfo = PatternStringParser.parseToPatternInfo(patternString);
-                buildReference.setPatternInfo(patternInfo);
+                buildReference.setPatternInfo(patternInfo, NumberFormat.Field.COMPACT);
                 precomputedMods.put(patternString, buildReference.createImmutable());
             }
         }
@@ -148,7 +149,7 @@ public class CompactNotation extends Notation {
                 // Overwrite the PatternInfo in the existing modMiddle.
                 assert micros.modMiddle instanceof MutablePatternModifier;
                 ParsedPatternInfo patternInfo = PatternStringParser.parseToPatternInfo(patternString);
-                ((MutablePatternModifier) micros.modMiddle).setPatternInfo(patternInfo);
+                ((MutablePatternModifier) micros.modMiddle).setPatternInfo(patternInfo, NumberFormat.Field.COMPACT);
             }
 
             // We already performed rounding. Do not perform it again.
index 17fbe912d8b077c4bc8f3f0129e5adf0e9d59c95..19b9b142a6ec0ac4741fe9d3e6511650b11137be 100644 (file)
@@ -322,7 +322,7 @@ class NumberFormatterImpl {
         // Middle modifier (patterns, positive/negative, currency symbols, percent)
         // The default middle modifier is weak (thus the false argument).
         MutablePatternModifier patternMod = new MutablePatternModifier(false);
-        patternMod.setPatternInfo((macros.affixProvider != null) ? macros.affixProvider : patternInfo);
+        patternMod.setPatternInfo((macros.affixProvider != null) ? macros.affixProvider : patternInfo, null);
         patternMod.setPatternAttributes(micros.sign, isPermille);
         if (patternMod.needsPlurals()) {
             if (rules == null) {
index e953a683a1515ed03ebd23d69bafda6f124b8f8f..4304bfa13edd05f5299d97354d699ebcef772470 100644 (file)
@@ -1966,6 +1966,11 @@ public abstract class NumberFormat extends UFormat {
          */
         public static final Field MEASURE_UNIT = new Field("measure unit");
 
+        /**
+         * @draft ICU 64
+         */
+        public static final Field COMPACT = new Field("compact");
+
         /**
          * Constructs a new instance of NumberFormat.Field with the given field
          * name.
index 6696daa2bea27f09954cc937c729f59676e10851..5c528c620b485c546eb71c8bbd17b3f61008e423 100644 (file)
@@ -204,14 +204,14 @@ public class AffixUtilsTest {
             String input = cas[0];
             String expected = cas[1];
             sb.clear();
-            AffixUtils.unescape(input, sb, 0, provider);
+            AffixUtils.unescape(input, sb, 0, provider, null);
             assertEquals("With symbol provider on <" + input + ">", expected, sb.toString());
         }
 
         // Test insertion position
         sb.clear();
         sb.append("abcdefg", null);
-        AffixUtils.unescape("-+%", sb, 4, provider);
+        AffixUtils.unescape("-+%", sb, 4, provider, null);
         assertEquals("Symbol provider into middle", "abcd123efg", sb.toString());
     }
 
@@ -237,7 +237,7 @@ public class AffixUtilsTest {
 
     private static String unescapeWithDefaults(String input) {
         NumberStringBuilder nsb = new NumberStringBuilder();
-        int length = AffixUtils.unescape(input, nsb, 0, DEFAULT_SYMBOL_PROVIDER);
+        int length = AffixUtils.unescape(input, nsb, 0, DEFAULT_SYMBOL_PROVIDER, null);
         assertEquals("Return value of unescape", nsb.length(), length);
         return nsb.toString();
     }
index 7f70a554155f3873cc6d03d8ae7c2ba6a0c8b8c2..5f2c13c6e0771188ea7fbc95c358a276ffc22d1c 100644 (file)
@@ -25,7 +25,7 @@ public class MutablePatternModifierTest {
     @Test
     public void basic() {
         MutablePatternModifier mod = new MutablePatternModifier(false);
-        mod.setPatternInfo(PatternStringParser.parseToPatternInfo("a0b"));
+        mod.setPatternInfo(PatternStringParser.parseToPatternInfo("a0b"), null);
         mod.setPatternAttributes(SignDisplay.AUTO, false);
         mod.setSymbols(DecimalFormatSymbols.getInstance(ULocale.ENGLISH),
                 Currency.getInstance("USD"),
@@ -51,7 +51,7 @@ public class MutablePatternModifierTest {
         assertEquals("a", getPrefix(mod));
         assertEquals("b", getSuffix(mod));
 
-        mod.setPatternInfo(PatternStringParser.parseToPatternInfo("a0b;c-0d"));
+        mod.setPatternInfo(PatternStringParser.parseToPatternInfo("a0b;c-0d"), null);
         mod.setPatternAttributes(SignDisplay.AUTO, false);
         mod.setNumberProperties(1, null);
         assertEquals("a", getPrefix(mod));
@@ -76,7 +76,7 @@ public class MutablePatternModifierTest {
     @Test
     public void mutableEqualsImmutable() {
         MutablePatternModifier mod = new MutablePatternModifier(false);
-        mod.setPatternInfo(PatternStringParser.parseToPatternInfo("a0b;c-0d"));
+        mod.setPatternInfo(PatternStringParser.parseToPatternInfo("a0b;c-0d"), null);
         mod.setPatternAttributes(SignDisplay.AUTO, false);
         mod.setSymbols(DecimalFormatSymbols.getInstance(ULocale.ENGLISH), null, UnitWidth.SHORT, null);
         DecimalQuantity fq = new DecimalQuantity_DualStorageBCD(1);
@@ -106,7 +106,7 @@ public class MutablePatternModifierTest {
     @Test
     public void patternWithNoPlaceholder() {
         MutablePatternModifier mod = new MutablePatternModifier(false);
-        mod.setPatternInfo(PatternStringParser.parseToPatternInfo("abc"));
+        mod.setPatternInfo(PatternStringParser.parseToPatternInfo("abc"), null);
         mod.setPatternAttributes(SignDisplay.AUTO, false);
         mod.setSymbols(DecimalFormatSymbols.getInstance(ULocale.ENGLISH),
                 Currency.getInstance("USD"),
index c857343048e96bf39067d35cde40676d904e3284..f59e981533ca0807cd483e7520f28dbba47a19c0 100644 (file)
@@ -2317,6 +2317,124 @@ public class NumberFormatterApiTest {
                     result,
                     expectedFieldPositions);
         }
+
+        {
+            String message = "Compact field basic";
+            FormattedNumber result = assertFormatSingle(
+                    message,
+                    "compact-short",
+                    NumberFormatter.with().notation(Notation.compactShort()),
+                    ULocale.US,
+                    65000,
+                    "65K");
+            Object[][] expectedFieldPositions = new Object[][] {
+                    // field, begin index, end index
+                    {NumberFormat.Field.INTEGER, 0, 2},
+                    {NumberFormat.Field.COMPACT, 2, 3}};
+            assertFieldPositions(
+                    message,
+                    result,
+                    expectedFieldPositions);
+        }
+
+        {
+            String message = "Compact field with spaces";
+            FormattedNumber result = assertFormatSingle(
+                    message,
+                    "compact-long",
+                    NumberFormatter.with().notation(Notation.compactLong()),
+                    ULocale.US,
+                    65000,
+                    "65 thousand");
+            Object[][] expectedFieldPositions = new Object[][] {
+                    // field, begin index, end index
+                    {NumberFormat.Field.INTEGER, 0, 2},
+                    {NumberFormat.Field.COMPACT, 3, 11}};
+            assertFieldPositions(
+                    message,
+                    result,
+                    expectedFieldPositions);
+        }
+
+        {
+            String message = "Compact field with inner space";
+            FormattedNumber result = assertFormatSingle(
+                    message,
+                    "compact-long",
+                    NumberFormatter.with().notation(Notation.compactLong()),
+                    new ULocale("fil"),  // locale with interesting data
+                    6000,
+                    "6 na libo");
+            Object[][] expectedFieldPositions = new Object[][] {
+                    // field, begin index, end index
+                    {NumberFormat.Field.INTEGER, 0, 1},
+                    {NumberFormat.Field.COMPACT, 2, 9}};
+            assertFieldPositions(
+                    message,
+                    result,
+                    expectedFieldPositions);
+        }
+
+        {
+            String message = "Compact field with bidi mark";
+            FormattedNumber result = assertFormatSingle(
+                    message,
+                    "compact-long",
+                    NumberFormatter.with().notation(Notation.compactLong()),
+                    new ULocale("he"),  // locale with interesting data
+                    6000,
+                    "\u200F6 אלף");
+            Object[][] expectedFieldPositions = new Object[][] {
+                    // field, begin index, end index
+                    {NumberFormat.Field.INTEGER, 1, 2},
+                    {NumberFormat.Field.COMPACT, 3, 6}};
+            assertFieldPositions(
+                    message,
+                    result,
+                    expectedFieldPositions);
+        }
+
+        {
+            String message = "Compact with currency fields";
+            FormattedNumber result = assertFormatSingle(
+                    message,
+                    "compact-short currency/USD",
+                    NumberFormatter.with().notation(Notation.compactShort()).unit(USD),
+                    new ULocale("sr_Latn"),  // locale with interesting data
+                    65000,
+                    "65 hilj. US$");
+            Object[][] expectedFieldPositions = new Object[][] {
+                    // field, begin index, end index
+                    {NumberFormat.Field.INTEGER, 0, 2},
+                    {NumberFormat.Field.COMPACT, 3, 8},
+                    {NumberFormat.Field.CURRENCY, 9, 12}};
+            assertFieldPositions(
+                    message,
+                    result,
+                    expectedFieldPositions);
+        }
+
+        {
+            String message = "Compact with measure unit fields";
+            FormattedNumber result = assertFormatSingle(
+                    message,
+                    "compact-long measure-unit/length-meter unit-width-full-name",
+                    NumberFormatter.with().notation(Notation.compactLong())
+                        .unit(MeasureUnit.METER)
+                        .unitWidth(UnitWidth.FULL_NAME),
+                    ULocale.US,
+                    65000,
+                    "65 thousand meters");
+            Object[][] expectedFieldPositions = new Object[][] {
+                    // field, begin index, end index
+                    {NumberFormat.Field.INTEGER, 0, 2},
+                    {NumberFormat.Field.COMPACT, 3, 11},
+                    {NumberFormat.Field.MEASURE_UNIT, 12, 18}};
+            assertFieldPositions(
+                    message,
+                    result,
+                    expectedFieldPositions);
+        }
     }
 
     /** Handler for serialization compatibility test suite. */