mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-13 08:53:20 +00:00
ICU-13177 Renaming files and ICU4C syncing.
X-SVN-Rev: 40459
This commit is contained in:
parent
6001089138
commit
0c9a9cf832
57 changed files with 1520 additions and 1417 deletions
icu4j/main
classes/core/src
com/ibm/icu
impl/number
AffixPatternProvider.javaCompactData.javaConstantAffixModifier.javaConstantMultiFieldModifier.javaCurrencySpacingEnabledModifier.javaCustomSymbolCurrency.javaDecimalFormatProperties.javaDecimalQuantity_AbstractBCD.javaDecimalQuantity_DualStorageBCD.javaLongNameHandler.javaMacroProps.javaMicroProps.javaMicroPropsGenerator.javaMicroPropsMutator.javaModifier.javaMultiplierImpl.javaMultiplierProducer.javaMutablePatternModifier.javaPadder.javaParameterizedModifier.javaPatternStringParser.javaPatternStringUtils.javaRoundingUtils.javaSimpleModifier.java
number
CompactNotation.javaCurrencyRounder.javaFormattedNumber.javaFractionRounder.javaGrouper.javaIntegerWidth.javaLocalizedNumberFormatter.javaNotation.javaNumberFormatter.javaNumberFormatterImpl.javaNumberFormatterSettings.javaNumberPropertyMapper.javaRounder.javaScientificNotation.javaSimpleNotation.javaUnlocalizedNumberFormatter.java
text
newapi
tests/core/src/com/ibm/icu
dev
data
test
impl/number
|
@ -1,6 +1,6 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package newapi.impl;
|
||||
package com.ibm.icu.impl.number;
|
||||
|
||||
public interface AffixPatternProvider {
|
||||
public static final class Flags {
|
|
@ -1,6 +1,6 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package newapi.impl;
|
||||
package com.ibm.icu.impl.number;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
@ -15,10 +15,12 @@ import com.ibm.icu.util.ICUException;
|
|||
import com.ibm.icu.util.ULocale;
|
||||
import com.ibm.icu.util.UResourceBundle;
|
||||
|
||||
import newapi.CompactNotation.CompactType;
|
||||
|
||||
public class CompactData implements MultiplierProducer {
|
||||
|
||||
public enum CompactType {
|
||||
DECIMAL, CURRENCY
|
||||
}
|
||||
|
||||
// A dummy object used when a "0" compact decimal entry is encountered. This is necessary
|
||||
// in order to prevent falling back to root. Object equality ("==") is intended.
|
||||
private static final String USE_FALLBACK = "<USE FALLBACK>";
|
|
@ -1,13 +1,7 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package com.ibm.icu.impl.number.modifiers;
|
||||
package com.ibm.icu.impl.number;
|
||||
|
||||
import com.ibm.icu.impl.number.Modifier;
|
||||
|
||||
// TODO: This class is currently unused, but it might be useful for something in the future.
|
||||
// Should probably be moved to a different package.
|
||||
|
||||
import com.ibm.icu.impl.number.NumberStringBuilder;
|
||||
import com.ibm.icu.text.NumberFormat.Field;
|
||||
|
||||
/**
|
|
@ -1,9 +1,7 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package com.ibm.icu.impl.number.modifiers;
|
||||
package com.ibm.icu.impl.number;
|
||||
|
||||
import com.ibm.icu.impl.number.Modifier;
|
||||
import com.ibm.icu.impl.number.NumberStringBuilder;
|
||||
import com.ibm.icu.text.NumberFormat.Field;
|
||||
|
||||
/**
|
|
@ -1,8 +1,7 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package com.ibm.icu.impl.number.modifiers;
|
||||
package com.ibm.icu.impl.number;
|
||||
|
||||
import com.ibm.icu.impl.number.NumberStringBuilder;
|
||||
import com.ibm.icu.text.DecimalFormatSymbols;
|
||||
import com.ibm.icu.text.NumberFormat;
|
||||
import com.ibm.icu.text.UnicodeSet;
|
|
@ -1,6 +1,6 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package newapi.impl;
|
||||
package com.ibm.icu.impl.number;
|
||||
|
||||
import com.ibm.icu.text.DecimalFormatSymbols;
|
||||
import com.ibm.icu.util.Currency;
|
|
@ -15,6 +15,7 @@ import java.text.ParsePosition;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
|
||||
import com.ibm.icu.impl.number.Padder.PadPosition;
|
||||
import com.ibm.icu.impl.number.Parse.GroupingMode;
|
||||
import com.ibm.icu.impl.number.Parse.ParseMode;
|
||||
import com.ibm.icu.text.CompactDecimalFormat.CompactStyle;
|
||||
|
@ -23,8 +24,6 @@ import com.ibm.icu.text.PluralRules;
|
|||
import com.ibm.icu.util.Currency;
|
||||
import com.ibm.icu.util.Currency.CurrencyUsage;
|
||||
|
||||
import newapi.impl.Padder.PadPosition;
|
||||
|
||||
public class DecimalFormatProperties implements Cloneable, Serializable {
|
||||
|
||||
private static final DecimalFormatProperties DEFAULT = new DecimalFormatProperties();
|
||||
|
|
|
@ -310,19 +310,6 @@ public abstract class DecimalQuantity_AbstractBCD implements DecimalQuantity {
|
|||
return precision == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DecimalQuantity createCopy() {
|
||||
if (this instanceof DecimalQuantity_64BitBCD) {
|
||||
return new DecimalQuantity_64BitBCD((DecimalQuantity_64BitBCD) this);
|
||||
} else if (this instanceof DecimalQuantity_ByteArrayBCD) {
|
||||
return new DecimalQuantity_ByteArrayBCD((DecimalQuantity_ByteArrayBCD) this);
|
||||
} else if (this instanceof DecimalQuantity_DualStorageBCD) {
|
||||
return new DecimalQuantity_DualStorageBCD((DecimalQuantity_DualStorageBCD) this);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Don't know how to copy " + this.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
public void setToInt(int n) {
|
||||
setBcdToZero();
|
||||
flags = 0;
|
||||
|
@ -423,6 +410,11 @@ public abstract class DecimalQuantity_AbstractBCD implements DecimalQuantity {
|
|||
* to digits. Since double arithmetic is inexact, the resulting digits may not be accurate.
|
||||
*/
|
||||
private void _setToDoubleFast(double n) {
|
||||
isApproximate = true;
|
||||
origDouble = n;
|
||||
origDelta = 0;
|
||||
|
||||
// NOTE: Unlike ICU4C, doubles are always IEEE 754 doubles.
|
||||
long ieeeBits = Double.doubleToLongBits(n);
|
||||
int exponent = (int) ((ieeeBits & 0x7ff0000000000000L) >> 52) - 0x3ff;
|
||||
|
||||
|
@ -432,10 +424,6 @@ public abstract class DecimalQuantity_AbstractBCD implements DecimalQuantity {
|
|||
return;
|
||||
}
|
||||
|
||||
isApproximate = true;
|
||||
origDouble = n;
|
||||
origDelta = 0;
|
||||
|
||||
// 3.3219... is log2(10)
|
||||
int fracLength = (int) ((52 - exponent) / 3.32192809489);
|
||||
if (fracLength >= 0) {
|
||||
|
|
|
@ -76,6 +76,11 @@ public final class DecimalQuantity_DualStorageBCD extends DecimalQuantity_Abstra
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DecimalQuantity createCopy() {
|
||||
return new DecimalQuantity_DualStorageBCD(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte getDigitPos(int position) {
|
||||
if (usingBytes) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package newapi.impl;
|
||||
package com.ibm.icu.impl.number;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
|
@ -11,9 +11,8 @@ import com.ibm.icu.impl.ICUResourceBundle;
|
|||
import com.ibm.icu.impl.SimpleFormatterImpl;
|
||||
import com.ibm.icu.impl.StandardPlural;
|
||||
import com.ibm.icu.impl.UResource;
|
||||
import com.ibm.icu.impl.number.DecimalQuantity;
|
||||
import com.ibm.icu.impl.number.modifiers.SimpleModifier;
|
||||
import com.ibm.icu.text.NumberFormat.Field;
|
||||
import com.ibm.icu.number.NumberFormatter.UnitWidth;
|
||||
import com.ibm.icu.text.NumberFormat;
|
||||
import com.ibm.icu.text.PluralRules;
|
||||
import com.ibm.icu.util.Currency;
|
||||
import com.ibm.icu.util.ICUException;
|
||||
|
@ -21,97 +20,17 @@ import com.ibm.icu.util.MeasureUnit;
|
|||
import com.ibm.icu.util.ULocale;
|
||||
import com.ibm.icu.util.UResourceBundle;
|
||||
|
||||
import newapi.NumberFormatter.UnitWidth;
|
||||
|
||||
public class LongNameHandler implements MicroPropsGenerator {
|
||||
|
||||
private final Map<StandardPlural, SimpleModifier> modifiers;
|
||||
private PluralRules rules;
|
||||
private MicroPropsGenerator parent;
|
||||
//////////////////////////
|
||||
/// BEGIN DATA LOADING ///
|
||||
//////////////////////////
|
||||
|
||||
private LongNameHandler(Map<StandardPlural, SimpleModifier> modifiers) {
|
||||
this.modifiers = modifiers;
|
||||
}
|
||||
|
||||
/** For use by the "safe" code path */
|
||||
private LongNameHandler(LongNameHandler other) {
|
||||
this.modifiers = other.modifiers;
|
||||
}
|
||||
|
||||
public static LongNameHandler forCurrencyLongNames(ULocale loc, Currency currency) {
|
||||
Map<String, String> data = CurrencyData.provider.getInstance(loc, true).getUnitPatterns();
|
||||
Map<StandardPlural, SimpleModifier> result = new EnumMap<StandardPlural, SimpleModifier>(StandardPlural.class);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Map.Entry<String, String> e : data.entrySet()) {
|
||||
String pluralKeyword = e.getKey();
|
||||
StandardPlural plural = StandardPlural.fromString(e.getKey());
|
||||
String longName = currency.getName(loc, Currency.PLURAL_LONG_NAME, pluralKeyword, null);
|
||||
String simpleFormat = e.getValue();
|
||||
// Example pattern from data: "{0} {1}"
|
||||
// Example output after find-and-replace: "{0} US dollars"
|
||||
simpleFormat = simpleFormat.replace("{1}", longName);
|
||||
String compiled = SimpleFormatterImpl.compileToStringMinMaxArguments(simpleFormat, sb, 1, 1);
|
||||
SimpleModifier mod = new SimpleModifier(compiled, Field.CURRENCY, false);
|
||||
result.put(plural, mod);
|
||||
}
|
||||
return new LongNameHandler(result);
|
||||
}
|
||||
|
||||
public static LongNameHandler forMeasureUnit(ULocale loc, MeasureUnit unit, UnitWidth width) {
|
||||
Map<StandardPlural, String> simpleFormats = getMeasureData(loc, unit, width);
|
||||
Map<StandardPlural, SimpleModifier> result = new EnumMap<StandardPlural, SimpleModifier>(StandardPlural.class);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (StandardPlural plural : StandardPlural.VALUES) {
|
||||
String simpleFormat = simpleFormats.get(plural);
|
||||
if (simpleFormat == null) {
|
||||
simpleFormat = simpleFormats.get(StandardPlural.OTHER);
|
||||
}
|
||||
if (simpleFormat == null) {
|
||||
// There should always be data in the "other" plural variant.
|
||||
throw new ICUException("Could not find data in 'other' plural variant for unit " + unit);
|
||||
}
|
||||
String compiled = SimpleFormatterImpl.compileToStringMinMaxArguments(simpleFormat, sb, 1, 1);
|
||||
// TODO: What field to use for units?
|
||||
SimpleModifier mod = new SimpleModifier(compiled, null, false);
|
||||
result.put(plural, mod);
|
||||
}
|
||||
return new LongNameHandler(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies locale data and inserts a long-name handler into the quantity chain.
|
||||
*
|
||||
* @param rules
|
||||
* The PluralRules instance to reference.
|
||||
* @param parent
|
||||
* The old head of the quantity chain.
|
||||
* @return The new head of the quantity chain.
|
||||
*/
|
||||
public MicroPropsGenerator withLocaleData(PluralRules rules, MicroPropsGenerator parent) {
|
||||
this.rules = rules;
|
||||
this.parent = parent;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MicroProps processQuantity(DecimalQuantity quantity) {
|
||||
MicroProps micros = parent.processQuantity(quantity);
|
||||
// TODO: Avoid the copy here?
|
||||
DecimalQuantity copy = quantity.createCopy();
|
||||
micros.rounding.apply(copy);
|
||||
micros.modOuter = modifiers.get(copy.getStandardPlural(rules));
|
||||
return micros;
|
||||
}
|
||||
|
||||
///////////////////////////////////////
|
||||
/// BEGIN MEASURE UNIT DATA LOADING ///
|
||||
///////////////////////////////////////
|
||||
|
||||
private static final class MeasureUnitSink extends UResource.Sink {
|
||||
private static final class PluralTableSink extends UResource.Sink {
|
||||
|
||||
Map<StandardPlural, String> output;
|
||||
|
||||
public MeasureUnitSink(Map<StandardPlural, String> output) {
|
||||
public PluralTableSink(Map<StandardPlural, String> output) {
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
|
@ -132,9 +51,11 @@ public class LongNameHandler implements MicroPropsGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
private static Map<StandardPlural, String> getMeasureData(ULocale locale, MeasureUnit unit, UnitWidth width) {
|
||||
ICUResourceBundle resource = (ICUResourceBundle) UResourceBundle.getBundleInstance(ICUData.ICU_UNIT_BASE_NAME,
|
||||
locale);
|
||||
private static void getMeasureData(ULocale locale, MeasureUnit unit, UnitWidth width,
|
||||
Map<StandardPlural, String> output) {
|
||||
PluralTableSink sink = new PluralTableSink(output);
|
||||
ICUResourceBundle resource;
|
||||
resource = (ICUResourceBundle) UResourceBundle.getBundleInstance(ICUData.ICU_UNIT_BASE_NAME, locale);
|
||||
StringBuilder key = new StringBuilder();
|
||||
key.append("units");
|
||||
if (width == UnitWidth.NARROW) {
|
||||
|
@ -146,13 +67,89 @@ public class LongNameHandler implements MicroPropsGenerator {
|
|||
key.append(unit.getType());
|
||||
key.append("/");
|
||||
key.append(unit.getSubtype());
|
||||
Map<StandardPlural, String> output = new EnumMap<StandardPlural, String>(StandardPlural.class);
|
||||
MeasureUnitSink sink = new MeasureUnitSink(output);
|
||||
resource.getAllItemsWithFallback(key.toString(), sink);
|
||||
return output;
|
||||
}
|
||||
|
||||
/////////////////////////////////////
|
||||
/// END MEASURE UNIT DATA LOADING ///
|
||||
/////////////////////////////////////
|
||||
private static void getCurrencyLongNameData(ULocale locale, Currency currency, Map<StandardPlural, String> output) {
|
||||
// In ICU4J, this method gets a CurrencyData from CurrencyData.provider.
|
||||
// TODO(ICU4J): Implement this without going through CurrencyData, like in ICU4C?
|
||||
Map<String, String> data = CurrencyData.provider.getInstance(locale, true).getUnitPatterns();
|
||||
for (Map.Entry<String, String> e : data.entrySet()) {
|
||||
String pluralKeyword = e.getKey();
|
||||
StandardPlural plural = StandardPlural.fromString(e.getKey());
|
||||
String longName = currency.getName(locale, Currency.PLURAL_LONG_NAME, pluralKeyword, null);
|
||||
String simpleFormat = e.getValue();
|
||||
// Example pattern from data: "{0} {1}"
|
||||
// Example output after find-and-replace: "{0} US dollars"
|
||||
simpleFormat = simpleFormat.replace("{1}", longName);
|
||||
// String compiled = SimpleFormatterImpl.compileToStringMinMaxArguments(simpleFormat, sb, 1, 1);
|
||||
// SimpleModifier mod = new SimpleModifier(compiled, Field.CURRENCY, false);
|
||||
output.put(plural, simpleFormat);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////
|
||||
/// END DATA LOADING ///
|
||||
////////////////////////
|
||||
|
||||
private final Map<StandardPlural, SimpleModifier> modifiers;
|
||||
private final PluralRules rules;
|
||||
private final MicroPropsGenerator parent;
|
||||
|
||||
private LongNameHandler(Map<StandardPlural, SimpleModifier> modifiers, PluralRules rules,
|
||||
MicroPropsGenerator parent) {
|
||||
this.modifiers = modifiers;
|
||||
this.rules = rules;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public static LongNameHandler forCurrencyLongNames(ULocale locale, Currency currency, PluralRules rules,
|
||||
MicroPropsGenerator parent) {
|
||||
Map<StandardPlural, String> simpleFormats = new EnumMap<StandardPlural, String>(StandardPlural.class);
|
||||
getCurrencyLongNameData(locale, currency, simpleFormats);
|
||||
// TODO(ICU4J): Reduce the number of object creations here?
|
||||
Map<StandardPlural, SimpleModifier> modifiers = new EnumMap<StandardPlural, SimpleModifier>(
|
||||
StandardPlural.class);
|
||||
simpleFormatsToModifiers(simpleFormats, null, modifiers);
|
||||
return new LongNameHandler(modifiers, rules, parent);
|
||||
}
|
||||
|
||||
public static LongNameHandler forMeasureUnit(ULocale locale, MeasureUnit unit, UnitWidth width, PluralRules rules,
|
||||
MicroPropsGenerator parent) {
|
||||
Map<StandardPlural, String> simpleFormats = new EnumMap<StandardPlural, String>(StandardPlural.class);
|
||||
getMeasureData(locale, unit, width, simpleFormats);
|
||||
// TODO: What field to use for units?
|
||||
// TODO(ICU4J): Reduce the number of object creations here?
|
||||
Map<StandardPlural, SimpleModifier> modifiers = new EnumMap<StandardPlural, SimpleModifier>(
|
||||
StandardPlural.class);
|
||||
simpleFormatsToModifiers(simpleFormats, null, modifiers);
|
||||
return new LongNameHandler(modifiers, rules, parent);
|
||||
}
|
||||
|
||||
private static void simpleFormatsToModifiers(Map<StandardPlural, String> simpleFormats, NumberFormat.Field field,
|
||||
Map<StandardPlural, SimpleModifier> output) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (StandardPlural plural : StandardPlural.VALUES) {
|
||||
String simpleFormat = simpleFormats.get(plural);
|
||||
if (simpleFormat == null) {
|
||||
simpleFormat = simpleFormats.get(StandardPlural.OTHER);
|
||||
}
|
||||
if (simpleFormat == null) {
|
||||
// There should always be data in the "other" plural variant.
|
||||
throw new ICUException("Could not find data in 'other' plural variant with field " + field);
|
||||
}
|
||||
String compiled = SimpleFormatterImpl.compileToStringMinMaxArguments(simpleFormat, sb, 1, 1);
|
||||
output.put(plural, new SimpleModifier(compiled, null, false));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MicroProps processQuantity(DecimalQuantity quantity) {
|
||||
MicroProps micros = parent.processQuantity(quantity);
|
||||
// TODO: Avoid the copy here?
|
||||
DecimalQuantity copy = quantity.createCopy();
|
||||
micros.rounding.apply(copy);
|
||||
micros.modOuter = modifiers.get(copy.getStandardPlural(rules));
|
||||
return micros;
|
||||
}
|
||||
}
|
|
@ -1,21 +1,20 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package newapi.impl;
|
||||
package com.ibm.icu.impl.number;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import com.ibm.icu.number.Grouper;
|
||||
import com.ibm.icu.number.IntegerWidth;
|
||||
import com.ibm.icu.number.Notation;
|
||||
import com.ibm.icu.number.NumberFormatter.DecimalSeparatorDisplay;
|
||||
import com.ibm.icu.number.NumberFormatter.SignDisplay;
|
||||
import com.ibm.icu.number.NumberFormatter.UnitWidth;
|
||||
import com.ibm.icu.number.Rounder;
|
||||
import com.ibm.icu.text.PluralRules;
|
||||
import com.ibm.icu.util.MeasureUnit;
|
||||
import com.ibm.icu.util.ULocale;
|
||||
|
||||
import newapi.Grouper;
|
||||
import newapi.IntegerWidth;
|
||||
import newapi.Notation;
|
||||
import newapi.NumberFormatter.DecimalMarkDisplay;
|
||||
import newapi.NumberFormatter.SignDisplay;
|
||||
import newapi.NumberFormatter.UnitWidth;
|
||||
import newapi.Rounder;
|
||||
|
||||
public class MacroProps implements Cloneable {
|
||||
public Notation notation;
|
||||
public MeasureUnit unit;
|
||||
|
@ -26,7 +25,7 @@ public class MacroProps implements Cloneable {
|
|||
public Object symbols;
|
||||
public UnitWidth unitWidth;
|
||||
public SignDisplay sign;
|
||||
public DecimalMarkDisplay decimal;
|
||||
public DecimalSeparatorDisplay decimal;
|
||||
public AffixPatternProvider affixProvider; // not in API; for JDK compatibility mode only
|
||||
public MultiplierImpl multiplier; // not in API; for JDK compatibility mode only
|
||||
public PluralRules rules; // not in API; could be made public in the future
|
|
@ -1,23 +1,20 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package newapi.impl;
|
||||
package com.ibm.icu.impl.number;
|
||||
|
||||
import com.ibm.icu.impl.number.DecimalQuantity;
|
||||
import com.ibm.icu.impl.number.Modifier;
|
||||
import com.ibm.icu.number.Grouper;
|
||||
import com.ibm.icu.number.IntegerWidth;
|
||||
import com.ibm.icu.number.Rounder;
|
||||
import com.ibm.icu.number.NumberFormatter.DecimalSeparatorDisplay;
|
||||
import com.ibm.icu.number.NumberFormatter.SignDisplay;
|
||||
import com.ibm.icu.text.DecimalFormatSymbols;
|
||||
|
||||
import newapi.Grouper;
|
||||
import newapi.IntegerWidth;
|
||||
import newapi.NumberFormatter.DecimalMarkDisplay;
|
||||
import newapi.NumberFormatter.SignDisplay;
|
||||
import newapi.Rounder;
|
||||
|
||||
public class MicroProps implements Cloneable, MicroPropsGenerator {
|
||||
// Populated globally:
|
||||
public SignDisplay sign;
|
||||
public DecimalFormatSymbols symbols;
|
||||
public Padder padding;
|
||||
public DecimalMarkDisplay decimal;
|
||||
public DecimalSeparatorDisplay decimal;
|
||||
public IntegerWidth integerWidth;
|
||||
|
||||
// Populated by notation/unit:
|
||||
|
@ -26,7 +23,6 @@ public class MicroProps implements Cloneable, MicroPropsGenerator {
|
|||
public Modifier modInner;
|
||||
public Rounder rounding;
|
||||
public Grouper grouping;
|
||||
public int multiplier;
|
||||
public boolean useCurrency;
|
||||
|
||||
// Internal fields:
|
|
@ -1,8 +1,6 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package newapi.impl;
|
||||
|
||||
import com.ibm.icu.impl.number.DecimalQuantity;
|
||||
package com.ibm.icu.impl.number;
|
||||
|
||||
/**
|
||||
* This interface is used when all number formatting settings, including the locale, are known, except for the quantity
|
|
@ -1,6 +1,6 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package newapi.impl;
|
||||
package com.ibm.icu.impl.number;
|
||||
|
||||
/**
|
||||
* @author sffc
|
|
@ -2,8 +2,6 @@
|
|||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package com.ibm.icu.impl.number;
|
||||
|
||||
import newapi.impl.MutablePatternModifier;
|
||||
|
||||
/**
|
||||
* A Modifier is an object that can be passed through the formatting pipeline until it is finally applied to the string
|
||||
* builder. A Modifier usually contains a prefix and a suffix that are applied, but it could contain something else,
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package newapi.impl;
|
||||
package com.ibm.icu.impl.number;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import com.ibm.icu.impl.number.DecimalQuantity;
|
||||
|
||||
public class MultiplierImpl implements MicroPropsGenerator, Cloneable {
|
||||
final int magnitudeMultiplier;
|
||||
final BigDecimal bigDecimalMultiplier;
|
|
@ -1,6 +1,6 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package newapi.impl;
|
||||
package com.ibm.icu.impl.number;
|
||||
|
||||
public interface MultiplierProducer {
|
||||
int getMultiplier(int magnitude);
|
|
@ -1,24 +1,15 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package newapi.impl;
|
||||
package com.ibm.icu.impl.number;
|
||||
|
||||
import com.ibm.icu.impl.StandardPlural;
|
||||
import com.ibm.icu.impl.number.AffixUtils;
|
||||
import com.ibm.icu.impl.number.AffixUtils.SymbolProvider;
|
||||
import com.ibm.icu.impl.number.DecimalQuantity;
|
||||
import com.ibm.icu.impl.number.Modifier;
|
||||
import com.ibm.icu.impl.number.NumberStringBuilder;
|
||||
import com.ibm.icu.impl.number.ParameterizedModifier;
|
||||
import com.ibm.icu.impl.number.PatternStringParser;
|
||||
import com.ibm.icu.impl.number.modifiers.ConstantMultiFieldModifier;
|
||||
import com.ibm.icu.impl.number.modifiers.CurrencySpacingEnabledModifier;
|
||||
import com.ibm.icu.number.NumberFormatter.SignDisplay;
|
||||
import com.ibm.icu.number.NumberFormatter.UnitWidth;
|
||||
import com.ibm.icu.text.DecimalFormatSymbols;
|
||||
import com.ibm.icu.text.PluralRules;
|
||||
import com.ibm.icu.util.Currency;
|
||||
|
||||
import newapi.NumberFormatter.SignDisplay;
|
||||
import newapi.NumberFormatter.UnitWidth;
|
||||
|
||||
/**
|
||||
* This class is a {@link Modifier} that wraps a decimal format pattern. It applies the pattern's affixes in
|
||||
* {@link Modifier#apply}.
|
||||
|
@ -37,8 +28,6 @@ import newapi.NumberFormatter.UnitWidth;
|
|||
* it from multiple threads! Instead, you can obtain a safe, immutable decimal format pattern modifier by calling
|
||||
* {@link MutablePatternModifier#createImmutable}, in effect treating this instance as a builder for the immutable
|
||||
* variant.
|
||||
*
|
||||
* FIXME: Make this package-private
|
||||
*/
|
||||
public class MutablePatternModifier implements Modifier, SymbolProvider, CharSequence, MicroPropsGenerator {
|
||||
|
||||
|
@ -331,9 +320,11 @@ public class MutablePatternModifier implements Modifier, SymbolProvider, CharSeq
|
|||
case AffixUtils.TYPE_PERMILLE:
|
||||
return symbols.getPerMillString();
|
||||
case AffixUtils.TYPE_CURRENCY_SINGLE:
|
||||
// UnitWidth ISO overrides the singular currency symbol.
|
||||
// UnitWidth ISO or HIDDEN overrides the singular currency symbol.
|
||||
if (unitWidth == UnitWidth.ISO_CODE) {
|
||||
return currency.getCurrencyCode();
|
||||
} else if (unitWidth == UnitWidth.HIDDEN) {
|
||||
return "";
|
||||
} else {
|
||||
return currency.getName(symbols.getULocale(), Currency.SYMBOL_NAME, null);
|
||||
}
|
|
@ -1,9 +1,6 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package newapi.impl;
|
||||
|
||||
import com.ibm.icu.impl.number.Modifier;
|
||||
import com.ibm.icu.impl.number.NumberStringBuilder;
|
||||
package com.ibm.icu.impl.number;
|
||||
|
||||
public class Padder {
|
||||
public static final String FALLBACK_PADDING_STRING = "\u0020"; // i.e. a space
|
||||
|
@ -45,7 +42,7 @@ public class Padder {
|
|||
}
|
||||
}
|
||||
|
||||
private static final Padder NONE = new Padder(null, -1, null);
|
||||
/* like package-private */ public static final Padder NONE = new Padder(null, -1, null);
|
||||
|
||||
String paddingString;
|
||||
int targetWidth;
|
||||
|
@ -53,7 +50,7 @@ public class Padder {
|
|||
|
||||
public Padder(String paddingString, int targetWidth, PadPosition position) {
|
||||
// TODO: Add a few default instances
|
||||
this.paddingString = (paddingString == null) ? " " : paddingString;
|
||||
this.paddingString = (paddingString == null) ? FALLBACK_PADDING_STRING : paddingString;
|
||||
this.targetWidth = targetWidth;
|
||||
this.position = (position == null) ? PadPosition.BEFORE_PREFIX : position;
|
||||
}
|
||||
|
@ -102,24 +99,6 @@ public class Padder {
|
|||
length += addPaddingHelper(paddingString, requiredPadding, string, rightIndex + length);
|
||||
}
|
||||
|
||||
// The length might not be exactly right due to currency spacing.
|
||||
// Make an adjustment if needed.
|
||||
while (string.codePointCount() < targetWidth) {
|
||||
int insertIndex = mod1.getPrefixLength() + mod2.getPrefixLength();
|
||||
switch (position) {
|
||||
case AFTER_PREFIX:
|
||||
insertIndex += leftIndex;
|
||||
break;
|
||||
case BEFORE_SUFFIX:
|
||||
insertIndex += rightIndex;
|
||||
break;
|
||||
default:
|
||||
// Should not happen since currency spacing is always on the inside.
|
||||
throw new AssertionError();
|
||||
}
|
||||
addPaddingHelper(paddingString, requiredPadding, string, insertIndex);
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package com.ibm.icu.impl.number;
|
||||
|
||||
import com.ibm.icu.impl.StandardPlural;
|
||||
|
||||
/**
|
||||
* A ParameterizedModifier by itself is NOT a Modifier. Rather, it wraps a data structure containing two or more
|
||||
* Modifiers and returns the modifier appropriate for the current situation.
|
||||
*/
|
||||
public class ParameterizedModifier {
|
||||
private final Modifier positive;
|
||||
private final Modifier negative;
|
||||
final Modifier[] mods;
|
||||
boolean frozen;
|
||||
|
||||
/**
|
||||
* This constructor populates the ParameterizedModifier with a single positive and negative form.
|
||||
*
|
||||
* <p>
|
||||
* If this constructor is used, a plural form CANNOT be passed to {@link #getModifier}.
|
||||
*/
|
||||
public ParameterizedModifier(Modifier positive, Modifier negative) {
|
||||
this.positive = positive;
|
||||
this.negative = negative;
|
||||
this.mods = null;
|
||||
this.frozen = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This constructor prepares the ParameterizedModifier to be populated with a positive and negative Modifier for
|
||||
* multiple plural forms.
|
||||
*
|
||||
* <p>
|
||||
* If this constructor is used, a plural form MUST be passed to {@link #getModifier}.
|
||||
*/
|
||||
public ParameterizedModifier() {
|
||||
this.positive = null;
|
||||
this.negative = null;
|
||||
this.mods = new Modifier[2 * StandardPlural.COUNT];
|
||||
this.frozen = false;
|
||||
}
|
||||
|
||||
public void setModifier(boolean isNegative, StandardPlural plural, Modifier mod) {
|
||||
assert !frozen;
|
||||
mods[getModIndex(isNegative, plural)] = mod;
|
||||
}
|
||||
|
||||
public void freeze() {
|
||||
frozen = true;
|
||||
}
|
||||
|
||||
public Modifier getModifier(boolean isNegative) {
|
||||
assert frozen;
|
||||
assert mods == null;
|
||||
return isNegative ? negative : positive;
|
||||
}
|
||||
|
||||
public Modifier getModifier(boolean isNegative, StandardPlural plural) {
|
||||
assert frozen;
|
||||
assert positive == null;
|
||||
return mods[getModIndex(isNegative, plural)];
|
||||
}
|
||||
|
||||
private static int getModIndex(boolean isNegative, StandardPlural plural) {
|
||||
return plural.ordinal() * 2 + (isNegative ? 1 : 0);
|
||||
}
|
||||
}
|
|
@ -2,8 +2,7 @@
|
|||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package com.ibm.icu.impl.number;
|
||||
|
||||
import newapi.impl.AffixPatternProvider;
|
||||
import newapi.impl.Padder.PadPosition;
|
||||
import com.ibm.icu.impl.number.Padder.PadPosition;
|
||||
|
||||
/** Implements a recursive descent parser for decimal format patterns. */
|
||||
public class PatternStringParser {
|
||||
|
|
|
@ -4,11 +4,9 @@ package com.ibm.icu.impl.number;
|
|||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import com.ibm.icu.impl.number.Padder.PadPosition;
|
||||
import com.ibm.icu.text.DecimalFormatSymbols;
|
||||
|
||||
import newapi.impl.Padder;
|
||||
import newapi.impl.Padder.PadPosition;
|
||||
|
||||
/**
|
||||
* Assorted utilities relating to decimal formatting pattern strings.
|
||||
*/
|
||||
|
|
|
@ -13,6 +13,17 @@ public class RoundingUtils {
|
|||
public static final int SECTION_MIDPOINT = 2;
|
||||
public static final int SECTION_UPPER = 3;
|
||||
|
||||
/**
|
||||
* The default rounding mode.
|
||||
*/
|
||||
public static final RoundingMode DEFAULT_ROUNDING_MODE = RoundingMode.HALF_EVEN;
|
||||
|
||||
/**
|
||||
* The maximum number of fraction places, integer numerals, or significant digits.
|
||||
* TODO: This does not feel like the best home for this value.
|
||||
*/
|
||||
public static final int MAX_INT_FRAC_SIG = 100;
|
||||
|
||||
/**
|
||||
* Converts a rounding mode and metadata about the quantity being rounded to a boolean determining
|
||||
* whether the value should be rounded toward infinity or toward zero.
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package com.ibm.icu.impl.number.modifiers;
|
||||
package com.ibm.icu.impl.number;
|
||||
|
||||
import com.ibm.icu.impl.SimpleFormatterImpl;
|
||||
import com.ibm.icu.impl.number.Modifier;
|
||||
import com.ibm.icu.impl.number.NumberStringBuilder;
|
||||
import com.ibm.icu.text.NumberFormat.Field;
|
||||
|
||||
/**
|
|
@ -1,6 +1,6 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package newapi;
|
||||
package com.ibm.icu.number;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
@ -8,34 +8,41 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
|
||||
import com.ibm.icu.impl.StandardPlural;
|
||||
import com.ibm.icu.impl.number.CompactData;
|
||||
import com.ibm.icu.impl.number.CompactData.CompactType;
|
||||
import com.ibm.icu.impl.number.DecimalQuantity;
|
||||
import com.ibm.icu.impl.number.MicroProps;
|
||||
import com.ibm.icu.impl.number.MicroPropsGenerator;
|
||||
import com.ibm.icu.impl.number.MutablePatternModifier;
|
||||
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.PluralRules;
|
||||
import com.ibm.icu.util.ULocale;
|
||||
|
||||
import newapi.impl.CompactData;
|
||||
import newapi.impl.MicroProps;
|
||||
import newapi.impl.MicroPropsGenerator;
|
||||
import newapi.impl.MutablePatternModifier;
|
||||
import newapi.impl.MutablePatternModifier.ImmutablePatternModifier;
|
||||
|
||||
/**
|
||||
* A class that defines the scientific notation style to be used when formatting numbers in NumberFormatter.
|
||||
*
|
||||
* <p>
|
||||
* This class exposes no public functionality. To create a CompactNotation, use one of the factory methods in
|
||||
* {@link Notation}.
|
||||
*
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public class CompactNotation extends Notation {
|
||||
|
||||
final CompactStyle compactStyle;
|
||||
final Map<String, Map<String, String>> compactCustomData;
|
||||
|
||||
public enum CompactType {
|
||||
DECIMAL, CURRENCY
|
||||
}
|
||||
|
||||
public CompactNotation(CompactStyle compactStyle) {
|
||||
/* package-private */ CompactNotation(CompactStyle compactStyle) {
|
||||
compactCustomData = null;
|
||||
this.compactStyle = compactStyle;
|
||||
}
|
||||
|
||||
public CompactNotation(Map<String, Map<String, String>> compactCustomData) {
|
||||
/* package-private */ CompactNotation(Map<String, Map<String, String>> compactCustomData) {
|
||||
compactStyle = null;
|
||||
this.compactCustomData = compactCustomData;
|
||||
}
|
||||
|
@ -118,7 +125,7 @@ public class CompactNotation extends Notation {
|
|||
// No need to take any action.
|
||||
} else if (precomputedMods != null) {
|
||||
// Safe code path.
|
||||
// Java uses a hash set here for O(1) lookup. C++ uses a linear search.
|
||||
// Java uses a hash set here for O(1) lookup. C++ uses a linear search.
|
||||
CompactModInfo info = precomputedMods.get(patternString);
|
||||
info.mod.applyToMicros(micros, quantity);
|
||||
numDigits = info.numDigits;
|
|
@ -1,28 +1,31 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package newapi;
|
||||
package com.ibm.icu.number;
|
||||
|
||||
import com.ibm.icu.util.Currency;
|
||||
import com.ibm.icu.util.Currency.CurrencyUsage;
|
||||
import com.ibm.icu.util.CurrencyAmount;
|
||||
import com.ibm.icu.util.Measure;
|
||||
import com.ibm.icu.util.MeasureUnit;
|
||||
|
||||
/** A rounding strategy parameterized by a currency. */
|
||||
/**
|
||||
* A class that defines a rounding strategy parameterized by a currency to be used when formatting numbers in
|
||||
* NumberFormatter.
|
||||
*
|
||||
* <p>
|
||||
* To create a CurrencyRounder, use one of the factory methods on Rounder.
|
||||
*
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public abstract class CurrencyRounder extends Rounder {
|
||||
|
||||
/* package-private */ CurrencyRounder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates a {@link com.ibm.icu.util.Currency} with this rounding strategy. Only applies to rounding strategies
|
||||
* returned from {@link #currency(CurrencyUsage)}.
|
||||
* Associates a currency with this rounding strategy.
|
||||
*
|
||||
* <p>
|
||||
* <strong>Calling this method is <em>not required</em></strong>, because the currency specified in
|
||||
* {@link NumberFormatterSettings#unit(MeasureUnit)} or via a {@link CurrencyAmount} passed into
|
||||
* {@link LocalizedNumberFormatter#format(Measure)} is automatically applied to currency rounding strategies.
|
||||
* However, this method enables you to override that automatic association.
|
||||
* <strong>Calling this method is <em>not required</em></strong>, because the currency specified in unit() or via a
|
||||
* CurrencyAmount passed into format(Measure) is automatically applied to currency rounding strategies. However,
|
||||
* this method enables you to override that automatic association.
|
||||
*
|
||||
* <p>
|
||||
* This method also enables numbers to be formatted using currency rounding rules without explicitly using a
|
||||
|
@ -30,7 +33,9 @@ public abstract class CurrencyRounder extends Rounder {
|
|||
*
|
||||
* @param currency
|
||||
* The currency to associate with this rounding strategy.
|
||||
* @return An immutable object for chaining.
|
||||
* @return A Rounder for chaining or passing to the NumberFormatter rounding() setter.
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public Rounder withCurrency(Currency currency) {
|
||||
if (currency != null) {
|
|
@ -1,6 +1,6 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package newapi;
|
||||
package com.ibm.icu.number;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
|
@ -9,12 +9,11 @@ import java.text.FieldPosition;
|
|||
import java.util.Arrays;
|
||||
|
||||
import com.ibm.icu.impl.number.DecimalQuantity;
|
||||
import com.ibm.icu.impl.number.MicroProps;
|
||||
import com.ibm.icu.impl.number.NumberStringBuilder;
|
||||
import com.ibm.icu.text.PluralRules.IFixedDecimal;
|
||||
import com.ibm.icu.util.ICUUncheckedIOException;
|
||||
|
||||
import newapi.impl.MicroProps;
|
||||
|
||||
public class FormattedNumber {
|
||||
NumberStringBuilder nsb;
|
||||
DecimalQuantity fq;
|
|
@ -1,10 +1,18 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package newapi;
|
||||
package com.ibm.icu.number;
|
||||
|
||||
import com.ibm.icu.impl.number.RoundingUtils;
|
||||
|
||||
/**
|
||||
* A rounding strategy based on a minimum and/or maximum number of fraction digits. Allows for a minimum or maximum
|
||||
* number of significant digits to be specified.
|
||||
* A class that defines a rounding strategy based on a number of fraction places and optionally significant digits to be
|
||||
* used when formatting numbers in NumberFormatter.
|
||||
*
|
||||
* <p>
|
||||
* To create a FractionRounder, use one of the factory methods on Rounder.
|
||||
*
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public abstract class FractionRounder extends Rounder {
|
||||
|
||||
|
@ -12,7 +20,7 @@ public abstract class FractionRounder extends Rounder {
|
|||
}
|
||||
|
||||
/**
|
||||
* Ensures that no less than this number of significant figures are retained when rounding according to fraction
|
||||
* Ensure that no less than this number of significant digits are retained when rounding according to fraction
|
||||
* rules.
|
||||
*
|
||||
* <p>
|
||||
|
@ -24,18 +32,21 @@ public abstract class FractionRounder extends Rounder {
|
|||
*
|
||||
* @param minSignificantDigits
|
||||
* The number of significant figures to guarantee.
|
||||
* @return An immutable object for chaining.
|
||||
* @return A Rounder for chaining or passing to the NumberFormatter rounding() setter.
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public Rounder withMinDigits(int minSignificantDigits) {
|
||||
if (minSignificantDigits > 0 && minSignificantDigits <= MAX_VALUE) {
|
||||
if (minSignificantDigits > 0 && minSignificantDigits <= RoundingUtils.MAX_INT_FRAC_SIG) {
|
||||
return constructFractionSignificant(this, minSignificantDigits, -1);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Significant digits must be between 0 and " + MAX_VALUE);
|
||||
throw new IllegalArgumentException(
|
||||
"Significant digits must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that no more than this number of significant figures are retained when rounding according to fraction
|
||||
* Ensure that no more than this number of significant digits are retained when rounding according to fraction
|
||||
* rules.
|
||||
*
|
||||
* <p>
|
||||
|
@ -48,13 +59,16 @@ public abstract class FractionRounder extends Rounder {
|
|||
*
|
||||
* @param maxSignificantDigits
|
||||
* Round the number to no more than this number of significant figures.
|
||||
* @return An immutable object for chaining.
|
||||
* @return A Rounder for chaining or passing to the NumberFormatter rounding() setter.
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public Rounder withMaxDigits(int maxSignificantDigits) {
|
||||
if (maxSignificantDigits > 0 && maxSignificantDigits <= MAX_VALUE) {
|
||||
if (maxSignificantDigits > 0 && maxSignificantDigits <= RoundingUtils.MAX_INT_FRAC_SIG) {
|
||||
return constructFractionSignificant(this, -1, maxSignificantDigits);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Significant digits must be between 0 and " + MAX_VALUE);
|
||||
throw new IllegalArgumentException(
|
||||
"Significant digits must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package newapi;
|
||||
package com.ibm.icu.number;
|
||||
|
||||
import com.ibm.icu.impl.number.DecimalQuantity;
|
||||
import com.ibm.icu.impl.number.PatternStringParser.ParsedPatternInfo;
|
||||
|
@ -31,7 +31,7 @@ public class Grouper {
|
|||
return DEFAULTS;
|
||||
}
|
||||
|
||||
public static Grouper min2() {
|
||||
public static Grouper minTwoDigits() {
|
||||
return MIN2;
|
||||
}
|
||||
|
||||
|
@ -64,10 +64,6 @@ public class Grouper {
|
|||
}
|
||||
}
|
||||
|
||||
static Grouper normalizeType(Grouper grouping, ParsedPatternInfo patternInfo) {
|
||||
return grouping.withLocaleData(patternInfo);
|
||||
}
|
||||
|
||||
Grouper withLocaleData(ParsedPatternInfo patternInfo) {
|
||||
if (grouping1 != -2) {
|
||||
return this;
|
|
@ -1,11 +1,13 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package newapi;
|
||||
package com.ibm.icu.number;
|
||||
|
||||
import com.ibm.icu.impl.number.RoundingUtils;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class IntegerWidth {
|
||||
|
||||
private static final IntegerWidth DEFAULT = new IntegerWidth(1, -1);
|
||||
/* package-private */ static final IntegerWidth DEFAULT = new IntegerWidth(1, -1);
|
||||
|
||||
final int minInt;
|
||||
final int maxInt;
|
||||
|
@ -18,22 +20,24 @@ public class IntegerWidth {
|
|||
public static IntegerWidth zeroFillTo(int minInt) {
|
||||
if (minInt == 1) {
|
||||
return DEFAULT;
|
||||
} else if (minInt >= 0 && minInt < Rounder.MAX_VALUE) {
|
||||
} else if (minInt >= 0 && minInt < RoundingUtils.MAX_INT_FRAC_SIG) {
|
||||
return new IntegerWidth(minInt, -1);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Integer digits must be between 0 and " + Rounder.MAX_VALUE);
|
||||
throw new IllegalArgumentException(
|
||||
"Integer digits must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG);
|
||||
}
|
||||
}
|
||||
|
||||
public IntegerWidth truncateAt(int maxInt) {
|
||||
if (maxInt == this.maxInt) {
|
||||
return this;
|
||||
} else if (maxInt >= 0 && maxInt < Rounder.MAX_VALUE) {
|
||||
} else if (maxInt >= 0 && maxInt < RoundingUtils.MAX_INT_FRAC_SIG) {
|
||||
return new IntegerWidth(minInt, maxInt);
|
||||
} else if (maxInt == -1) {
|
||||
return new IntegerWidth(minInt, maxInt);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Integer digits must be between 0 and " + Rounder.MAX_VALUE);
|
||||
throw new IllegalArgumentException(
|
||||
"Integer digits must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,19 +1,18 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package newapi;
|
||||
package com.ibm.icu.number;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
|
||||
|
||||
import com.ibm.icu.impl.number.DecimalQuantity;
|
||||
import com.ibm.icu.impl.number.DecimalQuantity_DualStorageBCD;
|
||||
import com.ibm.icu.impl.number.MacroProps;
|
||||
import com.ibm.icu.impl.number.MicroProps;
|
||||
import com.ibm.icu.impl.number.NumberStringBuilder;
|
||||
import com.ibm.icu.util.Measure;
|
||||
import com.ibm.icu.util.MeasureUnit;
|
||||
|
||||
import newapi.impl.MacroProps;
|
||||
import newapi.impl.MicroProps;
|
||||
|
||||
public class LocalizedNumberFormatter extends NumberFormatterSettings<LocalizedNumberFormatter> {
|
||||
|
||||
static final AtomicLongFieldUpdater<LocalizedNumberFormatter> callCount = AtomicLongFieldUpdater
|
||||
|
@ -60,6 +59,9 @@ public class LocalizedNumberFormatter extends NumberFormatterSettings<LocalizedN
|
|||
* This is the core entrypoint to the number formatting pipeline. It performs self-regulation: a static code path
|
||||
* for the first few calls, and compiling a more efficient data structure if called repeatedly.
|
||||
*
|
||||
* <p>
|
||||
* This function is very hot, being called in every call to the number formatting pipeline.
|
||||
*
|
||||
* @param fq
|
||||
* The quantity to be formatted.
|
||||
* @return The formatted number result.
|
||||
|
@ -70,9 +72,11 @@ public class LocalizedNumberFormatter extends NumberFormatterSettings<LocalizedN
|
|||
@Deprecated
|
||||
public FormattedNumber format(DecimalQuantity fq) {
|
||||
MacroProps macros = resolve();
|
||||
NumberStringBuilder string = new NumberStringBuilder();
|
||||
// TODO: Make this more like C++, where we get and then conditionally atomic-increment?
|
||||
// NOTE: In Java, the atomic increment logic is slightly different than ICU4C.
|
||||
// It seems to be more efficient to make just one function call instead of two.
|
||||
// Further benchmarking is required.
|
||||
long currentCount = callCount.incrementAndGet(this);
|
||||
NumberStringBuilder string = new NumberStringBuilder();
|
||||
MicroProps micros;
|
||||
if (currentCount == macros.threshold.longValue()) {
|
||||
compiled = NumberFormatterImpl.fromMacros(macros);
|
183
icu4j/main/classes/core/src/com/ibm/icu/number/Notation.java
Normal file
183
icu4j/main/classes/core/src/com/ibm/icu/number/Notation.java
Normal file
|
@ -0,0 +1,183 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package com.ibm.icu.number;
|
||||
|
||||
import com.ibm.icu.number.NumberFormatter.SignDisplay;
|
||||
import com.ibm.icu.text.CompactDecimalFormat.CompactStyle;
|
||||
|
||||
/**
|
||||
* A class that defines the notation style to be used when formatting numbers in NumberFormatter.
|
||||
*
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public class Notation {
|
||||
|
||||
// TODO: Support engineering intervals other than 3?
|
||||
private static final ScientificNotation SCIENTIFIC = new ScientificNotation(1, false, 1, SignDisplay.AUTO);
|
||||
private static final ScientificNotation ENGINEERING = new ScientificNotation(3, false, 1, SignDisplay.AUTO);
|
||||
private static final CompactNotation COMPACT_SHORT = new CompactNotation(CompactStyle.SHORT);
|
||||
private static final CompactNotation COMPACT_LONG = new CompactNotation(CompactStyle.LONG);
|
||||
private static final SimpleNotation SIMPLE = new SimpleNotation();
|
||||
|
||||
/* package-private */ Notation() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the number using scientific notation (also known as scientific form, standard index form, or standard form
|
||||
* in the UK). The format for scientific notation varies by locale; for example, many Western locales display the
|
||||
* number in the form "#E0", where the number is displayed with one digit before the decimal separator, zero or more
|
||||
* digits after the decimal separator, and the corresponding power of 10 displayed after the "E".
|
||||
*
|
||||
* <p>
|
||||
* Example outputs in <em>en-US</em> when printing 8.765E4 through 8.765E-3:
|
||||
*
|
||||
* <pre>
|
||||
* 8.765E4
|
||||
* 8.765E3
|
||||
* 8.765E2
|
||||
* 8.765E1
|
||||
* 8.765E0
|
||||
* 8.765E-1
|
||||
* 8.765E-2
|
||||
* 8.765E-3
|
||||
* 0E0
|
||||
* </pre>
|
||||
*
|
||||
* @return A ScientificNotation for chaining or passing to the NumberFormatter notation() setter.
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public static ScientificNotation scientific() {
|
||||
return SCIENTIFIC;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the number using engineering notation, a variant of scientific notation in which the exponent must be
|
||||
* divisible by 3.
|
||||
*
|
||||
* <p>
|
||||
* Example outputs in <em>en-US</em> when printing 8.765E4 through 8.765E-3:
|
||||
*
|
||||
* <pre>
|
||||
* 87.65E3
|
||||
* 8.765E3
|
||||
* 876.5E0
|
||||
* 87.65E0
|
||||
* 8.765E0
|
||||
* 876.5E-3
|
||||
* 87.65E-3
|
||||
* 8.765E-3
|
||||
* 0E0
|
||||
* </pre>
|
||||
*
|
||||
* @return A ScientificNotation for chaining or passing to the NumberFormatter notation() setter.
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public static ScientificNotation engineering() {
|
||||
return ENGINEERING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the number using short-form compact notation.
|
||||
*
|
||||
* <p>
|
||||
* <em>Compact notation</em>, defined in Unicode Technical Standard #35 Part 3 Section 2.4.1, prints numbers with
|
||||
* localized prefixes or suffixes corresponding to different powers of ten. Compact notation is similar to
|
||||
* engineering notation in how it scales numbers.
|
||||
*
|
||||
* <p>
|
||||
* Compact notation is ideal for displaying large numbers (over ~1000) to humans while at the same time minimizing
|
||||
* screen real estate.
|
||||
*
|
||||
* <p>
|
||||
* In short form, the powers of ten are abbreviated. In <em>en-US</em>, the abbreviations are "K" for thousands, "M"
|
||||
* for millions, "B" for billions, and "T" for trillions. Example outputs in <em>en-US</em> when printing 8.765E7
|
||||
* through 8.765E0:
|
||||
*
|
||||
* <pre>
|
||||
* 88M
|
||||
* 8.8M
|
||||
* 876K
|
||||
* 88K
|
||||
* 8.8K
|
||||
* 876
|
||||
* 88
|
||||
* 8.8
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* When compact notation is specified without an explicit rounding strategy, numbers are rounded off to the closest
|
||||
* integer after scaling the number by the corresponding power of 10, but with a digit shown after the decimal
|
||||
* separator if there is only one digit before the decimal separator. The default compact notation rounding strategy
|
||||
* is equivalent to:
|
||||
*
|
||||
* <pre>
|
||||
* Rounder.integer().withMinDigits(2)
|
||||
* </pre>
|
||||
*
|
||||
* @return A CompactNotation for passing to the NumberFormatter notation() setter.
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public static CompactNotation compactShort() {
|
||||
return COMPACT_SHORT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the number using long-form compact notation. For more information on compact notation, see
|
||||
* {@link #compactShort}.
|
||||
*
|
||||
* <p>
|
||||
* In long form, the powers of ten are spelled out fully. Example outputs in <em>en-US</em> when printing 8.765E7
|
||||
* through 8.765E0:
|
||||
*
|
||||
* <pre>
|
||||
* 88 million
|
||||
* 8.8 million
|
||||
* 876 thousand
|
||||
* 88 thousand
|
||||
* 8.8 thousand
|
||||
* 876
|
||||
* 88
|
||||
* 8.8
|
||||
* </pre>
|
||||
*
|
||||
* @return A CompactNotation for passing to the NumberFormatter notation() setter.
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public static CompactNotation compactLong() {
|
||||
return COMPACT_LONG;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the number using simple notation without any scaling by powers of ten. This is the default behavior.
|
||||
*
|
||||
* <p>
|
||||
* Since this is the default behavior, this method needs to be called only when it is necessary to override a
|
||||
* previous setting.
|
||||
*
|
||||
* <p>
|
||||
* Example outputs in <em>en-US</em> when printing 8.765E7 through 8.765E0:
|
||||
*
|
||||
* <pre>
|
||||
* 87,650,000
|
||||
* 8,765,000
|
||||
* 876,500
|
||||
* 87,650
|
||||
* 8,765
|
||||
* 876.5
|
||||
* 87.65
|
||||
* 8.765
|
||||
* </pre>
|
||||
*
|
||||
* @return A SimpleNotation for passing to the NumberFormatter notation() setter.
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public static SimpleNotation simple() {
|
||||
return SIMPLE;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,260 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package com.ibm.icu.number;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import com.ibm.icu.impl.number.DecimalFormatProperties;
|
||||
import com.ibm.icu.impl.number.MacroProps;
|
||||
import com.ibm.icu.text.DecimalFormatSymbols;
|
||||
import com.ibm.icu.util.ULocale;
|
||||
|
||||
public final class NumberFormatter {
|
||||
|
||||
private static final UnlocalizedNumberFormatter BASE = new UnlocalizedNumberFormatter();
|
||||
|
||||
/**
|
||||
* An enum declaring how to render units, including currencies. Example outputs when formatting 123 USD and 123
|
||||
* meters in <em>en-CA</em>:
|
||||
*
|
||||
* <p>
|
||||
* <ul>
|
||||
* <li>NARROW*: "$123.00" and "123 m"
|
||||
* <li>SHORT: "US$ 123.00" and "123 m"
|
||||
* <li>FULL_NAME: "123.00 US dollars" and "123 meters"
|
||||
* <li>ISO_CODE: "USD 123.00" and undefined behavior
|
||||
* <li>HIDDEN: "123.00" and "123"
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* * The narrow format for currencies is not currently supported; this is a known issue that will be fixed in a
|
||||
* future version. See #11666 for more information.
|
||||
*
|
||||
* <p>
|
||||
* This enum is similar to {@link com.ibm.icu.text.MeasureFormat.FormatWidth}.
|
||||
*
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public static enum UnitWidth {
|
||||
/**
|
||||
* Print an abbreviated version of the unit name. Similar to SHORT, but always use the shortest available
|
||||
* abbreviation or symbol. This option can be used when the context hints at the identity of the unit. For more
|
||||
* information on the difference between NARROW and SHORT, see SHORT.
|
||||
*
|
||||
* <p>
|
||||
* In CLDR, this option corresponds to the "Narrow" format for measure units and the "¤¤¤¤¤" placeholder for
|
||||
* currencies.
|
||||
*
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
NARROW,
|
||||
|
||||
/**
|
||||
* Print an abbreviated version of the unit name. Similar to NARROW, but use a slightly wider abbreviation or
|
||||
* symbol when there may be ambiguity. This is the default behavior.
|
||||
*
|
||||
* <p>
|
||||
* For example, in <em>es-US</em>, the SHORT form for Fahrenheit is "{0} °F", but the NARROW form is "{0}°",
|
||||
* since Fahrenheit is the customary unit for temperature in that locale.
|
||||
*
|
||||
* <p>
|
||||
* In CLDR, this option corresponds to the "Short" format for measure units and the "¤" placeholder for
|
||||
* currencies.
|
||||
*
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
SHORT,
|
||||
|
||||
/**
|
||||
* Print the full name of the unit, without any abbreviations.
|
||||
*
|
||||
* <p>
|
||||
* In CLDR, this option corresponds to the default format for measure units and the "¤¤¤" placeholder for
|
||||
* currencies.
|
||||
*
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
FULL_NAME,
|
||||
|
||||
/**
|
||||
* Use the three-digit ISO XXX code in place of the symbol for displaying currencies. The behavior of this
|
||||
* option is currently undefined for use with measure units.
|
||||
*
|
||||
* <p>
|
||||
* In CLDR, this option corresponds to the "¤¤" placeholder for currencies.
|
||||
*
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
ISO_CODE,
|
||||
|
||||
/**
|
||||
* Format the number according to the specified unit, but do not display the unit. For currencies, apply
|
||||
* monetary symbols and formats as with SHORT, but omit the currency symbol. For measure units, the behavior is
|
||||
* equivalent to not specifying the unit at all.
|
||||
*
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
HIDDEN,
|
||||
}
|
||||
|
||||
/**
|
||||
* An enum declaring how to denote positive and negative numbers. Example outputs when formatting 123 and -123 in
|
||||
* <em>en-US</em>:
|
||||
*
|
||||
* <p>
|
||||
* <ul>
|
||||
* <li>AUTO: "123" and "-123"
|
||||
* <li>ALWAYS: "+123" and "-123"
|
||||
* <li>NEVER: "123" and "123"
|
||||
* <li>ACCOUNTING: "$123" and "($123)"
|
||||
* <li>ACCOUNTING_ALWAYS: "+$123" and "($123)"
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* The exact format, including the position and the code point of the sign, differ by locale.
|
||||
*
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public static enum SignDisplay {
|
||||
/**
|
||||
* Show the minus sign on negative numbers, and do not show the sign on positive numbers. This is the default
|
||||
* behavior.
|
||||
*
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
AUTO,
|
||||
|
||||
/**
|
||||
* Show the minus sign on negative numbers and the plus sign on positive numbers.
|
||||
*
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
ALWAYS,
|
||||
|
||||
/**
|
||||
* Do not show the sign on positive or negative numbers.
|
||||
*
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
NEVER,
|
||||
|
||||
/**
|
||||
* Use the locale-dependent accounting format on negative numbers, and do not show the sign on positive numbers.
|
||||
*
|
||||
* <p>
|
||||
* The accounting format is defined in CLDR and varies by locale; in many Western locales, the format is a pair
|
||||
* of parentheses around the number.
|
||||
*
|
||||
* <p>
|
||||
* Note: Since CLDR defines the accounting format in the monetary context only, this option falls back to the
|
||||
* AUTO sign display strategy when formatting without a currency unit. This limitation may be lifted in the
|
||||
* future.
|
||||
*
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
ACCOUNTING,
|
||||
|
||||
/**
|
||||
* Use the locale-dependent accounting format on negative numbers, and show the plus sign on positive numbers.
|
||||
* For more information on the accounting format, see the ACCOUNTING sign display strategy.
|
||||
*
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
ACCOUNTING_ALWAYS,
|
||||
}
|
||||
|
||||
/**
|
||||
* An enum declaring how to render the decimal separator. Example outputs when formatting 1 and 1.1 in
|
||||
* <em>en-US</em>:
|
||||
*
|
||||
* <p>
|
||||
* <ul>
|
||||
* <li>AUTO: "1" and "1.1"
|
||||
* <li>ALWAYS: "1." and "1.1"
|
||||
* </ul>
|
||||
*/
|
||||
public static enum DecimalSeparatorDisplay {
|
||||
/**
|
||||
* Show the decimal separator when there are one or more digits to display after the separator, and do not show
|
||||
* it otherwise. This is the default behavior.
|
||||
*
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
AUTO,
|
||||
|
||||
/**
|
||||
* Always show the decimal separator, even if there are no digits to display after the separator.
|
||||
*
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
ALWAYS,
|
||||
}
|
||||
|
||||
/**
|
||||
* Use a default threshold of 3. This means that the third time .format() is called, the data structures get built
|
||||
* using the "safe" code path. The first two calls to .format() will trigger the unsafe code path.
|
||||
*/
|
||||
static final long DEFAULT_THRESHOLD = 3;
|
||||
|
||||
/**
|
||||
* Call this method at the beginning of a NumberFormatter fluent chain in which the locale is not currently known at
|
||||
* the call site.
|
||||
*
|
||||
* @return An {@link UnlocalizedNumberFormatter}, to be used for chaining.
|
||||
* @draft ICU 60
|
||||
*/
|
||||
public static UnlocalizedNumberFormatter with() {
|
||||
return BASE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method at the beginning of a NumberFormatter fluent chain in which the locale is known at the call
|
||||
* site.
|
||||
*
|
||||
* @param locale
|
||||
* The locale from which to load formats and symbols for number formatting.
|
||||
* @return A {@link LocalizedNumberFormatter}, to be used for chaining.
|
||||
* @draft ICU 60
|
||||
*/
|
||||
public static LocalizedNumberFormatter withLocale(Locale locale) {
|
||||
return BASE.locale(locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method at the beginning of a NumberFormatter fluent chain in which the locale is known at the call
|
||||
* site.
|
||||
*
|
||||
* @param locale
|
||||
* The locale from which to load formats and symbols for number formatting.
|
||||
* @return A {@link LocalizedNumberFormatter}, to be used for chaining.
|
||||
* @draft ICU 60
|
||||
*/
|
||||
public static LocalizedNumberFormatter withLocale(ULocale locale) {
|
||||
return BASE.locale(locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated ICU 60 This API is ICU internal only.
|
||||
*/
|
||||
@Deprecated
|
||||
public static UnlocalizedNumberFormatter fromDecimalFormat(DecimalFormatProperties properties,
|
||||
DecimalFormatSymbols symbols, DecimalFormatProperties exportedProperties) {
|
||||
MacroProps macros = NumberPropertyMapper.oldToNew(properties, symbols, exportedProperties);
|
||||
return NumberFormatter.with().macros(macros);
|
||||
}
|
||||
}
|
|
@ -1,31 +1,28 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package newapi;
|
||||
package com.ibm.icu.number;
|
||||
|
||||
import com.ibm.icu.impl.number.CompactData.CompactType;
|
||||
import com.ibm.icu.impl.number.ConstantAffixModifier;
|
||||
import com.ibm.icu.impl.number.DecimalQuantity;
|
||||
import com.ibm.icu.impl.number.LongNameHandler;
|
||||
import com.ibm.icu.impl.number.MacroProps;
|
||||
import com.ibm.icu.impl.number.MicroProps;
|
||||
import com.ibm.icu.impl.number.MicroPropsGenerator;
|
||||
import com.ibm.icu.impl.number.MutablePatternModifier;
|
||||
import com.ibm.icu.impl.number.NumberStringBuilder;
|
||||
import com.ibm.icu.impl.number.Padder;
|
||||
import com.ibm.icu.impl.number.PatternStringParser;
|
||||
import com.ibm.icu.impl.number.PatternStringParser.ParsedPatternInfo;
|
||||
import com.ibm.icu.impl.number.modifiers.ConstantAffixModifier;
|
||||
import com.ibm.icu.number.NumberFormatter.DecimalSeparatorDisplay;
|
||||
import com.ibm.icu.number.NumberFormatter.SignDisplay;
|
||||
import com.ibm.icu.number.NumberFormatter.UnitWidth;
|
||||
import com.ibm.icu.text.DecimalFormatSymbols;
|
||||
import com.ibm.icu.text.NumberFormat;
|
||||
import com.ibm.icu.text.NumberingSystem;
|
||||
import com.ibm.icu.text.PluralRules;
|
||||
import com.ibm.icu.util.Currency;
|
||||
import com.ibm.icu.util.Currency.CurrencyUsage;
|
||||
import com.ibm.icu.util.NoUnit;
|
||||
import com.ibm.icu.util.ULocale;
|
||||
|
||||
import newapi.CompactNotation.CompactType;
|
||||
import newapi.NumberFormatter.DecimalMarkDisplay;
|
||||
import newapi.NumberFormatter.SignDisplay;
|
||||
import newapi.NumberFormatter.UnitWidth;
|
||||
import newapi.impl.LongNameHandler;
|
||||
import newapi.impl.MacroProps;
|
||||
import newapi.impl.MicroProps;
|
||||
import newapi.impl.MicroPropsGenerator;
|
||||
import newapi.impl.MutablePatternModifier;
|
||||
import newapi.impl.Padder;
|
||||
import com.ibm.icu.util.MeasureUnit;
|
||||
|
||||
/**
|
||||
* This is the "brain" of the number formatting pipeline. It ties all the pieces together, taking in a MacroProps and a
|
||||
|
@ -67,6 +64,25 @@ class NumberFormatterImpl {
|
|||
|
||||
//////////
|
||||
|
||||
private static boolean unitIsCurrency(MeasureUnit unit) {
|
||||
// TODO: Check using "instanceof" operator instead?
|
||||
return unit != null && "currency".equals(unit.getType());
|
||||
}
|
||||
|
||||
private static boolean unitIsNoUnit(MeasureUnit unit) {
|
||||
// NOTE: In ICU4C, units cannot be null, and the default unit is a NoUnit.
|
||||
// In ICU4J, return TRUE for a null unit from this method.
|
||||
return unit == null || "none".equals(unit.getType());
|
||||
}
|
||||
|
||||
private static boolean unitIsPercent(MeasureUnit unit) {
|
||||
return unit != null && "percent".equals(unit.getSubtype());
|
||||
}
|
||||
|
||||
private static boolean unitIsPermille(MeasureUnit unit) {
|
||||
return unit != null && "permille".equals(unit.getSubtype());
|
||||
}
|
||||
|
||||
/**
|
||||
* Synthesizes the MacroProps into a MicroPropsGenerator. All information, including the locale, is encoded into the
|
||||
* MicroPropsGenerator, except for the quantity itself, which is left abstract and must be provided to the returned
|
||||
|
@ -81,119 +97,122 @@ class NumberFormatterImpl {
|
|||
* object is more expensive.
|
||||
*/
|
||||
private static MicroPropsGenerator macrosToMicroGenerator(MacroProps macros, boolean safe) {
|
||||
|
||||
String innerPattern = null;
|
||||
LongNameHandler longNames = null;
|
||||
Rounder defaultRounder = Rounder.unlimited();
|
||||
Currency currency = DEFAULT_CURRENCY;
|
||||
UnitWidth unitWidth = (macros.unitWidth == null) ? UnitWidth.SHORT : macros.unitWidth;
|
||||
boolean perMille = false;
|
||||
PluralRules rules = macros.rules;
|
||||
|
||||
// FIXME
|
||||
String nsName = NumberingSystem.getInstance(macros.loc).getName();
|
||||
|
||||
MicroProps micros = new MicroProps(safe);
|
||||
MicroPropsGenerator chain = micros;
|
||||
|
||||
// Copy over the simple settings
|
||||
micros.sign = macros.sign == null ? SignDisplay.AUTO : macros.sign;
|
||||
micros.decimal = macros.decimal == null ? DecimalMarkDisplay.AUTO : macros.decimal;
|
||||
micros.multiplier = 0;
|
||||
micros.integerWidth = macros.integerWidth == null ? IntegerWidth.zeroFillTo(1) : macros.integerWidth;
|
||||
|
||||
if (macros.unit == null || macros.unit == NoUnit.BASE) {
|
||||
// No units; default format
|
||||
innerPattern = NumberFormat.getPatternForStyle(macros.loc, NumberFormat.NUMBERSTYLE);
|
||||
} else if (macros.unit == NoUnit.PERCENT) {
|
||||
// Percent
|
||||
innerPattern = NumberFormat.getPatternForStyle(macros.loc, NumberFormat.PERCENTSTYLE);
|
||||
micros.multiplier += 2;
|
||||
} else if (macros.unit == NoUnit.PERMILLE) {
|
||||
// Permille
|
||||
innerPattern = NumberFormat.getPatternForStyle(macros.loc, NumberFormat.PERCENTSTYLE);
|
||||
micros.multiplier += 3;
|
||||
perMille = true;
|
||||
} else if (macros.unit instanceof Currency && macros.unitWidth != UnitWidth.FULL_NAME) {
|
||||
// Narrow, short, or ISO currency.
|
||||
// TODO: Although ACCOUNTING and ACCOUNTING_ALWAYS are only supported in currencies right now,
|
||||
// the API contract allows us to add support to other units.
|
||||
if (macros.sign == SignDisplay.ACCOUNTING || macros.sign == SignDisplay.ACCOUNTING_ALWAYS) {
|
||||
innerPattern = NumberFormat.getPatternForStyle(macros.loc, NumberFormat.ACCOUNTINGCURRENCYSTYLE);
|
||||
} else {
|
||||
innerPattern = NumberFormat.getPatternForStyle(macros.loc, NumberFormat.CURRENCYSTYLE);
|
||||
}
|
||||
defaultRounder = Rounder.currency(CurrencyUsage.STANDARD);
|
||||
currency = (Currency) macros.unit;
|
||||
micros.useCurrency = true;
|
||||
} else if (macros.unit instanceof Currency) {
|
||||
// Currency long name
|
||||
innerPattern = NumberFormat.getPatternForStyle(macros.loc, NumberFormat.NUMBERSTYLE);
|
||||
longNames = LongNameHandler.forCurrencyLongNames(macros.loc, (Currency) macros.unit);
|
||||
defaultRounder = Rounder.currency(CurrencyUsage.STANDARD);
|
||||
currency = (Currency) macros.unit;
|
||||
micros.useCurrency = true;
|
||||
} else {
|
||||
// MeasureUnit
|
||||
innerPattern = NumberFormat.getPatternForStyle(macros.loc, NumberFormat.NUMBERSTYLE);
|
||||
longNames = LongNameHandler.forMeasureUnit(macros.loc, macros.unit, unitWidth);
|
||||
}
|
||||
|
||||
// Parse the pattern, which is used for grouping and affixes only.
|
||||
ParsedPatternInfo patternInfo = PatternStringParser.parseToPatternInfo(innerPattern);
|
||||
|
||||
// Symbols
|
||||
// NOTE: C++ has a special class, SymbolsWrapper, in MacroProps. Java has all the resolution logic here
|
||||
// directly.
|
||||
if (macros.symbols == null) {
|
||||
micros.symbols = DecimalFormatSymbols.getInstance(macros.loc);
|
||||
} else if (macros.symbols instanceof DecimalFormatSymbols) {
|
||||
micros.symbols = (DecimalFormatSymbols) macros.symbols;
|
||||
} else if (macros.symbols instanceof NumberingSystem) {
|
||||
// TODO: Do this more efficiently. Will require modifying DecimalFormatSymbols.
|
||||
NumberingSystem ns = (NumberingSystem) macros.symbols;
|
||||
ULocale temp = macros.loc.setKeywordValue("numbers", ns.getName());
|
||||
micros.symbols = DecimalFormatSymbols.getInstance(temp);
|
||||
} else {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
// TODO: Normalize the currency (accept symbols from DecimalFormatSymbols)?
|
||||
// currency = CustomSymbolCurrency.resolve(currency, input.loc, micros.symbols);
|
||||
|
||||
// Pre-compute a few values for efficiency.
|
||||
boolean isCurrency = unitIsCurrency(macros.unit);
|
||||
boolean isNoUnit = unitIsNoUnit(macros.unit);
|
||||
boolean isPercent = isNoUnit && unitIsPercent(macros.unit);
|
||||
boolean isPermille = isNoUnit && unitIsPermille(macros.unit);
|
||||
boolean isCldrUnit = !isCurrency && !isNoUnit;
|
||||
boolean isAccounting = macros.sign == SignDisplay.ACCOUNTING || macros.sign == SignDisplay.ACCOUNTING_ALWAYS;
|
||||
Currency currency = isCurrency ? (Currency) macros.unit : DEFAULT_CURRENCY;
|
||||
UnitWidth unitWidth = UnitWidth.SHORT;
|
||||
if (macros.unitWidth != null) {
|
||||
unitWidth = macros.unitWidth;
|
||||
}
|
||||
PluralRules rules = macros.rules;
|
||||
|
||||
// Select the numbering system.
|
||||
NumberingSystem ns;
|
||||
if (macros.symbols instanceof NumberingSystem) {
|
||||
ns = (NumberingSystem) macros.symbols;
|
||||
} else {
|
||||
// TODO: Is there a way to avoid creating the NumberingSystem object?
|
||||
ns = NumberingSystem.getInstance(macros.loc);
|
||||
}
|
||||
String nsName = ns.getName();
|
||||
|
||||
// Load and parse the pattern string. It is used for grouping sizes and affixes only.
|
||||
int patternStyle;
|
||||
if (isPercent || isPermille) {
|
||||
patternStyle = NumberFormat.PERCENTSTYLE;
|
||||
} else if (!isCurrency || unitWidth == UnitWidth.FULL_NAME) {
|
||||
patternStyle = NumberFormat.NUMBERSTYLE;
|
||||
} else if (isAccounting) {
|
||||
// NOTE: Although ACCOUNTING and ACCOUNTING_ALWAYS are only supported in currencies right now,
|
||||
// the API contract allows us to add support to other units in the future.
|
||||
patternStyle = NumberFormat.ACCOUNTINGCURRENCYSTYLE;
|
||||
} else {
|
||||
patternStyle = NumberFormat.CURRENCYSTYLE;
|
||||
}
|
||||
String pattern = NumberFormat.getPatternForStyleAndNumberingSystem(macros.loc, nsName, patternStyle);
|
||||
ParsedPatternInfo patternInfo = PatternStringParser.parseToPatternInfo(pattern);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
/// START POPULATING THE DEFAULT MICROPROPS AND BUILDING THE MICROPROPS GENERATOR ///
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Symbols
|
||||
if (macros.symbols instanceof DecimalFormatSymbols) {
|
||||
micros.symbols = (DecimalFormatSymbols) macros.symbols;
|
||||
} else {
|
||||
micros.symbols = DecimalFormatSymbols.forNumberingSystem(macros.loc, ns);
|
||||
}
|
||||
|
||||
// Multiplier (compatibility mode value).
|
||||
// An int magnitude multiplier is used when not in compatibility mode to
|
||||
// reduce object creations.
|
||||
if (macros.multiplier != null) {
|
||||
chain = macros.multiplier.copyAndChain(chain);
|
||||
}
|
||||
|
||||
// Rounding strategy
|
||||
if (macros.rounder != null) {
|
||||
micros.rounding = Rounder.normalizeType(macros.rounder, currency);
|
||||
micros.rounding = macros.rounder;
|
||||
} else if (macros.notation instanceof CompactNotation) {
|
||||
micros.rounding = Rounder.COMPACT_STRATEGY;
|
||||
} else if (isCurrency) {
|
||||
micros.rounding = Rounder.MONETARY_STANDARD;
|
||||
} else {
|
||||
micros.rounding = Rounder.normalizeType(defaultRounder, currency);
|
||||
micros.rounding = Rounder.MAX_FRAC_6;
|
||||
}
|
||||
micros.rounding = micros.rounding.withLocaleData(currency);
|
||||
|
||||
// Grouping strategy
|
||||
if (macros.grouper != null) {
|
||||
micros.grouping = Grouper.normalizeType(macros.grouper, patternInfo);
|
||||
micros.grouping = macros.grouper;
|
||||
} else if (macros.notation instanceof CompactNotation) {
|
||||
// Compact notation uses minGrouping by default since ICU 59
|
||||
micros.grouping = Grouper.normalizeType(Grouper.min2(), patternInfo);
|
||||
micros.grouping = Grouper.minTwoDigits();
|
||||
} else {
|
||||
micros.grouping = Grouper.normalizeType(Grouper.defaults(), patternInfo);
|
||||
micros.grouping = Grouper.defaults();
|
||||
}
|
||||
micros.grouping = micros.grouping.withLocaleData(patternInfo);
|
||||
|
||||
// Padding strategy
|
||||
if (macros.padder != null) {
|
||||
micros.padding = macros.padder;
|
||||
} else {
|
||||
micros.padding = Padder.none();
|
||||
micros.padding = Padder.NONE;
|
||||
}
|
||||
|
||||
// Integer width
|
||||
if (macros.integerWidth != null) {
|
||||
micros.integerWidth = macros.integerWidth;
|
||||
} else {
|
||||
micros.integerWidth = IntegerWidth.DEFAULT;
|
||||
}
|
||||
|
||||
// Sign display
|
||||
if (macros.sign != null) {
|
||||
micros.sign = macros.sign;
|
||||
} else {
|
||||
micros.sign = SignDisplay.AUTO;
|
||||
}
|
||||
|
||||
// Decimal mark display
|
||||
if (macros.decimal != null) {
|
||||
micros.decimal = macros.decimal;
|
||||
} else {
|
||||
micros.decimal = DecimalSeparatorDisplay.AUTO;
|
||||
}
|
||||
|
||||
// Use monetary separator symbols
|
||||
micros.useCurrency = isCurrency;
|
||||
|
||||
// Inner modifier (scientific notation)
|
||||
if (macros.notation instanceof ScientificNotation) {
|
||||
chain = ((ScientificNotation) macros.notation).withLocaleData(micros.symbols, safe, chain);
|
||||
|
@ -206,7 +225,7 @@ class NumberFormatterImpl {
|
|||
// The default middle modifier is weak (thus the false argument).
|
||||
MutablePatternModifier patternMod = new MutablePatternModifier(false);
|
||||
patternMod.setPatternInfo((macros.affixProvider != null) ? macros.affixProvider : patternInfo);
|
||||
patternMod.setPatternAttributes(micros.sign, perMille);
|
||||
patternMod.setPatternAttributes(micros.sign, isPermille);
|
||||
if (patternMod.needsPlurals()) {
|
||||
if (rules == null) {
|
||||
// Lazily create PluralRules
|
||||
|
@ -223,12 +242,18 @@ class NumberFormatterImpl {
|
|||
}
|
||||
|
||||
// Outer modifier (CLDR units and currency long names)
|
||||
if (longNames != null) {
|
||||
if (isCldrUnit) {
|
||||
if (rules == null) {
|
||||
// Lazily create PluralRules
|
||||
rules = PluralRules.forLocale(macros.loc);
|
||||
}
|
||||
chain = longNames.withLocaleData(rules, chain);
|
||||
chain = LongNameHandler.forMeasureUnit(macros.loc, macros.unit, unitWidth, rules, chain);
|
||||
} else if (isCurrency && unitWidth == UnitWidth.FULL_NAME) {
|
||||
if (rules == null) {
|
||||
// Lazily create PluralRules
|
||||
rules = PluralRules.forLocale(macros.loc);
|
||||
}
|
||||
chain = LongNameHandler.forCurrencyLongNames(macros.loc, currency, rules, chain);
|
||||
} else {
|
||||
// No outer modifier required
|
||||
micros.modOuter = ConstantAffixModifier.EMPTY;
|
||||
|
@ -265,7 +290,6 @@ class NumberFormatterImpl {
|
|||
* The output string. Will be mutated.
|
||||
*/
|
||||
private static void microsToString(MicroProps micros, DecimalQuantity quantity, NumberStringBuilder string) {
|
||||
quantity.adjustMagnitude(micros.multiplier);
|
||||
micros.rounding.apply(quantity);
|
||||
if (micros.integerWidth.maxInt == -1) {
|
||||
quantity.setIntegerLength(micros.integerWidth.minInt, Integer.MAX_VALUE);
|
||||
|
@ -298,7 +322,7 @@ class NumberFormatterImpl {
|
|||
length += writeIntegerDigits(micros, quantity, string);
|
||||
|
||||
// Add the decimal point
|
||||
if (quantity.getLowerDisplayMagnitude() < 0 || micros.decimal == DecimalMarkDisplay.ALWAYS) {
|
||||
if (quantity.getLowerDisplayMagnitude() < 0 || micros.decimal == DecimalSeparatorDisplay.ALWAYS) {
|
||||
length += string.insert(length, micros.useCurrency ? micros.symbols.getMonetaryDecimalSeparatorString()
|
||||
: micros.symbols.getDecimalSeparatorString(), NumberFormat.Field.DECIMAL_SEPARATOR);
|
||||
}
|
|
@ -1,7 +1,12 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package newapi;
|
||||
package com.ibm.icu.number;
|
||||
|
||||
import com.ibm.icu.impl.number.MacroProps;
|
||||
import com.ibm.icu.impl.number.Padder;
|
||||
import com.ibm.icu.number.NumberFormatter.DecimalSeparatorDisplay;
|
||||
import com.ibm.icu.number.NumberFormatter.SignDisplay;
|
||||
import com.ibm.icu.number.NumberFormatter.UnitWidth;
|
||||
import com.ibm.icu.text.DecimalFormatSymbols;
|
||||
import com.ibm.icu.text.MeasureFormat.FormatWidth;
|
||||
import com.ibm.icu.text.NumberingSystem;
|
||||
|
@ -11,12 +16,6 @@ import com.ibm.icu.util.MeasureUnit;
|
|||
import com.ibm.icu.util.NoUnit;
|
||||
import com.ibm.icu.util.ULocale;
|
||||
|
||||
import newapi.NumberFormatter.DecimalMarkDisplay;
|
||||
import newapi.NumberFormatter.SignDisplay;
|
||||
import newapi.NumberFormatter.UnitWidth;
|
||||
import newapi.impl.MacroProps;
|
||||
import newapi.impl.Padder;
|
||||
|
||||
/**
|
||||
* An abstract base class for specifying settings related to number formatting. This class is implemented by
|
||||
* {@link UnlocalizedNumberFormatter} and {@link LocalizedNumberFormatter}.
|
||||
|
@ -342,7 +341,7 @@ public abstract class NumberFormatterSettings<T extends NumberFormatterSettings<
|
|||
return create(KEY_SIGN, style);
|
||||
}
|
||||
|
||||
public T decimal(DecimalMarkDisplay style) {
|
||||
public T decimal(DecimalSeparatorDisplay style) {
|
||||
return create(KEY_DECIMAL, style);
|
||||
}
|
||||
|
||||
|
@ -364,11 +363,6 @@ public abstract class NumberFormatterSettings<T extends NumberFormatterSettings<
|
|||
return create(KEY_THRESHOLD, threshold);
|
||||
}
|
||||
|
||||
/** Non-public method */
|
||||
public String toSkeleton() {
|
||||
return SkeletonBuilder.macrosToSkeleton(resolve());
|
||||
}
|
||||
|
||||
abstract T create(int key, Object value);
|
||||
|
||||
MacroProps resolve() {
|
||||
|
@ -438,7 +432,7 @@ public abstract class NumberFormatterSettings<T extends NumberFormatterSettings<
|
|||
break;
|
||||
case KEY_DECIMAL:
|
||||
if (macros.decimal == null) {
|
||||
macros.decimal = (DecimalMarkDisplay) current.value;
|
||||
macros.decimal = (DecimalSeparatorDisplay) current.value;
|
||||
}
|
||||
break;
|
||||
case KEY_THRESHOLD:
|
|
@ -1,15 +1,25 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package newapi;
|
||||
package com.ibm.icu.number;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
|
||||
import com.ibm.icu.impl.StandardPlural;
|
||||
import com.ibm.icu.impl.number.AffixPatternProvider;
|
||||
import com.ibm.icu.impl.number.AffixUtils;
|
||||
import com.ibm.icu.impl.number.CustomSymbolCurrency;
|
||||
import com.ibm.icu.impl.number.DecimalFormatProperties;
|
||||
import com.ibm.icu.impl.number.MacroProps;
|
||||
import com.ibm.icu.impl.number.MultiplierImpl;
|
||||
import com.ibm.icu.impl.number.Padder;
|
||||
import com.ibm.icu.impl.number.PatternStringParser;
|
||||
import com.ibm.icu.impl.number.PatternStringParser.ParsedPatternInfo;
|
||||
import com.ibm.icu.number.NumberFormatter.DecimalSeparatorDisplay;
|
||||
import com.ibm.icu.number.NumberFormatter.SignDisplay;
|
||||
import com.ibm.icu.number.Rounder.FractionRounderImpl;
|
||||
import com.ibm.icu.number.Rounder.IncrementRounderImpl;
|
||||
import com.ibm.icu.number.Rounder.SignificantRounderImpl;
|
||||
import com.ibm.icu.impl.number.RoundingUtils;
|
||||
import com.ibm.icu.text.CompactDecimalFormat.CompactStyle;
|
||||
import com.ibm.icu.text.CurrencyPluralInfo;
|
||||
|
@ -18,17 +28,6 @@ import com.ibm.icu.util.Currency;
|
|||
import com.ibm.icu.util.Currency.CurrencyUsage;
|
||||
import com.ibm.icu.util.ULocale;
|
||||
|
||||
import newapi.NumberFormatter.DecimalMarkDisplay;
|
||||
import newapi.NumberFormatter.SignDisplay;
|
||||
import newapi.Rounder.FractionRounderImpl;
|
||||
import newapi.Rounder.IncrementRounderImpl;
|
||||
import newapi.Rounder.SignificantRounderImpl;
|
||||
import newapi.impl.AffixPatternProvider;
|
||||
import newapi.impl.CustomSymbolCurrency;
|
||||
import newapi.impl.MacroProps;
|
||||
import newapi.impl.MultiplierImpl;
|
||||
import newapi.impl.Padder;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This class, as well as NumberFormatterImpl, could go into the impl package, but they depend on too many
|
||||
|
@ -198,8 +197,8 @@ final class NumberPropertyMapper {
|
|||
// DECIMAL MARK ALWAYS SHOWN //
|
||||
///////////////////////////////
|
||||
|
||||
macros.decimal = properties.getDecimalSeparatorAlwaysShown() ? DecimalMarkDisplay.ALWAYS
|
||||
: DecimalMarkDisplay.AUTO;
|
||||
macros.decimal = properties.getDecimalSeparatorAlwaysShown() ? DecimalSeparatorDisplay.ALWAYS
|
||||
: DecimalSeparatorDisplay.AUTO;
|
||||
|
||||
///////////////////////
|
||||
// SIGN ALWAYS SHOWN //
|
|
@ -1,39 +1,50 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package newapi;
|
||||
package com.ibm.icu.number;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
import com.ibm.icu.impl.number.DecimalQuantity;
|
||||
import com.ibm.icu.impl.number.MultiplierProducer;
|
||||
import com.ibm.icu.impl.number.RoundingUtils;
|
||||
import com.ibm.icu.util.Currency;
|
||||
import com.ibm.icu.util.Currency.CurrencyUsage;
|
||||
|
||||
import newapi.impl.MultiplierProducer;
|
||||
|
||||
/**
|
||||
* A class that defines the rounding strategy to be used when formatting numbers in NumberFormatter.
|
||||
*
|
||||
* <p>
|
||||
* To create a Rounder, use one of the factory methods.
|
||||
*
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public abstract class Rounder implements Cloneable {
|
||||
|
||||
// FIXME
|
||||
/** @internal */
|
||||
public static final int MAX_VALUE = 100;
|
||||
|
||||
/* package-private final */ MathContext mathContext;
|
||||
|
||||
/* package-private */ Rounder() {
|
||||
mathContext = RoundingUtils.mathContextUnlimited(RoundingMode.HALF_EVEN);
|
||||
mathContext = RoundingUtils.mathContextUnlimited(RoundingUtils.DEFAULT_ROUNDING_MODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show all available digits to full precision.
|
||||
*
|
||||
* <p>
|
||||
* <strong>NOTE:</strong> If you are formatting <em>doubles</em> and you know that the number of fraction places or
|
||||
* significant digits is bounded, consider using {@link #maxFraction} or {@link #maxDigits} instead to maximize
|
||||
* performance.
|
||||
* <strong>NOTE:</strong> When formatting a <em>double</em>, this method, along with {@link #minFraction} and
|
||||
* {@link #minDigits}, will trigger complex algorithm similar to <em>Dragon4</em> to determine the low-order digits
|
||||
* and the number of digits to display based on the value of the double. If the number of fraction places or
|
||||
* significant digits can be bounded, consider using {@link #maxFraction} or {@link #maxDigits} instead to maximize
|
||||
* performance. For more information, read the following blog post.
|
||||
*
|
||||
* @return A rounding strategy for {@link NumberFormatterSettings#rounding}.
|
||||
* <p>
|
||||
* http://www.serpentine.com/blog/2011/06/29/here-be-dragons-advances-in-problems-you-didnt-even-know-you-had/
|
||||
*
|
||||
* @return A Rounder for chaining or passing to the NumberFormatter rounding() setter.
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public static Rounder unlimited() {
|
||||
return constructInfinite();
|
||||
|
@ -42,18 +53,20 @@ public abstract class Rounder implements Cloneable {
|
|||
/**
|
||||
* Show numbers rounded if necessary to the nearest integer.
|
||||
*
|
||||
* @return A rounding strategy for {@link NumberFormatterSettings#rounding}.
|
||||
* @return A FractionRounder for chaining or passing to the NumberFormatter rounding() setter.
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public static FractionRounder integer() {
|
||||
return constructFraction(0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show numbers rounded if necessary to a certain number of fraction places (digits after the decimal mark).
|
||||
* Additionally, pad with zeros to ensure that this number digits are always shown.
|
||||
* Show numbers rounded if necessary to a certain number of fraction places (numerals after the decimal separator).
|
||||
* Additionally, pad with zeros to ensure that this number of places are always shown.
|
||||
*
|
||||
* <p>
|
||||
* Example output with minMaxFractionDigits = 3:
|
||||
* Example output with minMaxFractionPlaces = 3:
|
||||
*
|
||||
* <p>
|
||||
* 87,650.000<br>
|
||||
|
@ -69,106 +82,196 @@ public abstract class Rounder implements Cloneable {
|
|||
* <p>
|
||||
* This method is equivalent to {@link #minMaxFraction} with both arguments equal.
|
||||
*
|
||||
* @param minMaxFractionDigits
|
||||
* The minimum and maximum number of digits to display after the decimal mark (rounding if too long or
|
||||
* padding with zeros if too short).
|
||||
* @return A rounding strategy for {@link NumberFormatterSettings#rounding}.
|
||||
* @param minMaxFractionPlaces
|
||||
* The minimum and maximum number of numerals to display after the decimal separator (rounding if too
|
||||
* long or padding with zeros if too short).
|
||||
* @return A FractionRounder for chaining or passing to the NumberFormatter rounding() setter.
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public static FractionRounder fixedFraction(int minMaxFractionDigits) {
|
||||
if (minMaxFractionDigits >= 0 && minMaxFractionDigits <= MAX_VALUE) {
|
||||
return constructFraction(minMaxFractionDigits, minMaxFractionDigits);
|
||||
public static FractionRounder fixedFraction(int minMaxFractionPlaces) {
|
||||
if (minMaxFractionPlaces >= 0 && minMaxFractionPlaces <= RoundingUtils.MAX_INT_FRAC_SIG) {
|
||||
return constructFraction(minMaxFractionPlaces, minMaxFractionPlaces);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Fraction length must be between 0 and " + MAX_VALUE);
|
||||
throw new IllegalArgumentException(
|
||||
"Fraction length must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Always show a certain number of digits after the decimal mark, padding with zeros if necessary. Do not perform
|
||||
* rounding (display numbers to their full precision).
|
||||
* Always show at least a certain number of fraction places after the decimal separator, padding with zeros if
|
||||
* necessary. Do not perform rounding (display numbers to their full precision).
|
||||
*
|
||||
* <p>
|
||||
* <strong>NOTE:</strong> If you are formatting <em>doubles</em> and you know that the number of fraction places is
|
||||
* bounded, consider using {@link #fixedFraction} or {@link #minMaxFraction} instead to maximize performance.
|
||||
* <strong>NOTE:</strong> If you are formatting <em>doubles</em>, see the performance note in {@link #unlimited}.
|
||||
*
|
||||
* @param minFractionDigits
|
||||
* The minimum number of digits to display after the decimal mark (padding with zeros if necessary).
|
||||
* @return A rounding strategy for {@link NumberFormatterSettings#rounding}.
|
||||
* @param minFractionPlaces
|
||||
* The minimum number of numerals to display after the decimal separator (padding with zeros if
|
||||
* necessary).
|
||||
* @return A FractionRounder for chaining or passing to the NumberFormatter rounding() setter.
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public static FractionRounder minFraction(int minFractionDigits) {
|
||||
if (minFractionDigits >= 0 && minFractionDigits < MAX_VALUE) {
|
||||
return constructFraction(minFractionDigits, -1);
|
||||
public static FractionRounder minFraction(int minFractionPlaces) {
|
||||
if (minFractionPlaces >= 0 && minFractionPlaces < RoundingUtils.MAX_INT_FRAC_SIG) {
|
||||
return constructFraction(minFractionPlaces, -1);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Fraction length must be between 0 and " + MAX_VALUE);
|
||||
throw new IllegalArgumentException(
|
||||
"Fraction length must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show numbers rounded if necessary to a certain number of fraction places (digits after the decimal mark). Unlike
|
||||
* the other fraction rounding strategies, this strategy does <em>not</em> pad zeros to the end of the number.
|
||||
* Show numbers rounded if necessary to a certain number of fraction places (numerals after the decimal separator).
|
||||
* Unlike the other fraction rounding strategies, this strategy does <em>not</em> pad zeros to the end of the
|
||||
* number.
|
||||
*
|
||||
* @param maxFractionDigits
|
||||
* The maximum number of digits to display after the decimal mark (rounding if necessary).
|
||||
* @return A rounding strategy for {@link NumberFormatterSettings#rounding}.
|
||||
* @param maxFractionPlaces
|
||||
* The maximum number of numerals to display after the decimal mark (rounding if necessary).
|
||||
* @return A FractionRounder for chaining or passing to the NumberFormatter rounding() setter.
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public static FractionRounder maxFraction(int maxFractionDigits) {
|
||||
if (maxFractionDigits >= 0 && maxFractionDigits < MAX_VALUE) {
|
||||
return constructFraction(0, maxFractionDigits);
|
||||
public static FractionRounder maxFraction(int maxFractionPlaces) {
|
||||
if (maxFractionPlaces >= 0 && maxFractionPlaces < RoundingUtils.MAX_INT_FRAC_SIG) {
|
||||
return constructFraction(0, maxFractionPlaces);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Fraction length must be between 0 and " + MAX_VALUE);
|
||||
throw new IllegalArgumentException(
|
||||
"Fraction length must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show numbers rounded if necessary to a certain number of fraction places (digits after the decimal mark); in
|
||||
* addition, always show a certain number of digits after the decimal mark, padding with zeros if necessary.
|
||||
* Show numbers rounded if necessary to a certain number of fraction places (numerals after the decimal separator);
|
||||
* in addition, always show at least a certain number of places after the decimal separator, padding with zeros if
|
||||
* necessary.
|
||||
*
|
||||
* @param minFractionDigits
|
||||
* The minimum number of digits to display after the decimal mark (padding with zeros if necessary).
|
||||
* @param maxFractionDigits
|
||||
* The maximum number of digits to display after the decimal mark (rounding if necessary).
|
||||
* @return A rounding strategy for {@link NumberFormatterSettings#rounding}.
|
||||
* @param minFractionPlaces
|
||||
* The minimum number of numerals to display after the decimal separator (padding with zeros if
|
||||
* necessary).
|
||||
* @param maxFractionPlaces
|
||||
* The maximum number of numerals to display after the decimal separator (rounding if necessary).
|
||||
* @return A FractionRounder for chaining or passing to the NumberFormatter rounding() setter.
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public static FractionRounder minMaxFraction(int minFractionDigits, int maxFractionDigits) {
|
||||
if (minFractionDigits >= 0 && maxFractionDigits <= MAX_VALUE && minFractionDigits <= maxFractionDigits) {
|
||||
return constructFraction(minFractionDigits, maxFractionDigits);
|
||||
public static FractionRounder minMaxFraction(int minFractionPlaces, int maxFractionPlaces) {
|
||||
if (minFractionPlaces >= 0 && maxFractionPlaces <= RoundingUtils.MAX_INT_FRAC_SIG
|
||||
&& minFractionPlaces <= maxFractionPlaces) {
|
||||
return constructFraction(minFractionPlaces, maxFractionPlaces);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Fraction length must be between 0 and " + MAX_VALUE);
|
||||
throw new IllegalArgumentException(
|
||||
"Fraction length must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show numbers rounded if necessary to a certain number of significant digits or significant figures. Additionally,
|
||||
* pad with zeros to ensure that this number of significant digits/figures are always shown.
|
||||
*
|
||||
* <p>
|
||||
* This method is equivalent to {@link #minMaxDigits} with both arguments equal.
|
||||
*
|
||||
* @param minMaxSignificantDigits
|
||||
* The minimum and maximum number of significant digits to display (rounding if too long or padding with
|
||||
* zeros if too short).
|
||||
* @return A Rounder for chaining or passing to the NumberFormatter rounding() setter.
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public static Rounder fixedDigits(int minMaxSignificantDigits) {
|
||||
if (minMaxSignificantDigits > 0 && minMaxSignificantDigits <= MAX_VALUE) {
|
||||
if (minMaxSignificantDigits > 0 && minMaxSignificantDigits <= RoundingUtils.MAX_INT_FRAC_SIG) {
|
||||
return constructSignificant(minMaxSignificantDigits, minMaxSignificantDigits);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Significant digits must be between 0 and " + MAX_VALUE);
|
||||
throw new IllegalArgumentException(
|
||||
"Significant digits must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Always show at least a certain number of significant digits/figures, padding with zeros if necessary. Do not
|
||||
* perform rounding (display numbers to their full precision).
|
||||
*
|
||||
* <p>
|
||||
* <strong>NOTE:</strong> If you are formatting <em>doubles</em>, see the performance note in {@link #unlimited}.
|
||||
*
|
||||
* @param minSignificantDigits
|
||||
* The minimum number of significant digits to display (padding with zeros if too short).
|
||||
* @return A Rounder for chaining or passing to the NumberFormatter rounding() setter.
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public static Rounder minDigits(int minSignificantDigits) {
|
||||
if (minSignificantDigits > 0 && minSignificantDigits <= MAX_VALUE) {
|
||||
if (minSignificantDigits > 0 && minSignificantDigits <= RoundingUtils.MAX_INT_FRAC_SIG) {
|
||||
return constructSignificant(minSignificantDigits, -1);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Significant digits must be between 0 and " + MAX_VALUE);
|
||||
throw new IllegalArgumentException(
|
||||
"Significant digits must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show numbers rounded if necessary to a certain number of significant digits/figures.
|
||||
*
|
||||
* @param maxSignificantDigits
|
||||
* The maximum number of significant digits to display (rounding if too long).
|
||||
* @return A Rounder for chaining or passing to the NumberFormatter rounding() setter.
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public static Rounder maxDigits(int maxSignificantDigits) {
|
||||
if (maxSignificantDigits > 0 && maxSignificantDigits <= MAX_VALUE) {
|
||||
if (maxSignificantDigits > 0 && maxSignificantDigits <= RoundingUtils.MAX_INT_FRAC_SIG) {
|
||||
return constructSignificant(0, maxSignificantDigits);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Significant digits must be between 0 and " + MAX_VALUE);
|
||||
throw new IllegalArgumentException(
|
||||
"Significant digits must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show numbers rounded if necessary to a certain number of significant digits/figures; in addition, always show at
|
||||
* least a certain number of significant digits, padding with zeros if necessary.
|
||||
*
|
||||
* @param minSignificantDigits
|
||||
* The minimum number of significant digits to display (padding with zeros if necessary).
|
||||
* @param maxSignificantDigits
|
||||
* The maximum number of significant digits to display (rounding if necessary).
|
||||
* @return A Rounder for chaining or passing to the NumberFormatter rounding() setter.
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public static Rounder minMaxDigits(int minSignificantDigits, int maxSignificantDigits) {
|
||||
if (minSignificantDigits > 0 && maxSignificantDigits <= MAX_VALUE
|
||||
if (minSignificantDigits > 0 && maxSignificantDigits <= RoundingUtils.MAX_INT_FRAC_SIG
|
||||
&& minSignificantDigits <= maxSignificantDigits) {
|
||||
return constructSignificant(minSignificantDigits, maxSignificantDigits);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Significant digits must be between 0 and " + MAX_VALUE);
|
||||
throw new IllegalArgumentException(
|
||||
"Significant digits must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show numbers rounded if necessary to the closest multiple of a certain rounding increment. For example, if the
|
||||
* rounding increment is 0.5, then round 1.2 to 1 and round 1.3 to 1.5.
|
||||
*
|
||||
* <p>
|
||||
* In order to ensure that numbers are padded to the appropriate number of fraction places, set the scale on the
|
||||
* rounding increment BigDecimal. For example, to round to the nearest 0.5 and always display 2 numerals after the
|
||||
* decimal separator (to display 1.2 as "1.00" and 1.3 as "1.50"), you can run:
|
||||
*
|
||||
* <pre>
|
||||
* Rounder.increment(new BigDecimal("0.50"))
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* For more information on the scale of Java BigDecimal, see {@link java.math.BigDecimal#scale()}.
|
||||
*
|
||||
* @param roundingIncrement
|
||||
* The increment to which to round numbers.
|
||||
* @return A Rounder for chaining or passing to the NumberFormatter rounding() setter.
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public static Rounder increment(BigDecimal roundingIncrement) {
|
||||
if (roundingIncrement != null && roundingIncrement.compareTo(BigDecimal.ZERO) > 0) {
|
||||
return constructIncrement(roundingIncrement);
|
||||
|
@ -177,6 +280,23 @@ public abstract class Rounder implements Cloneable {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show numbers rounded and padded according to the rules for the currency unit. The most common rounding settings
|
||||
* for currencies include <code>Rounder.fixedFraction(2)</code>, <code>Rounder.integer()</code>, and
|
||||
* <code>Rounder.increment(0.05)</code> for cash transactions ("nickel rounding").
|
||||
*
|
||||
* <p>
|
||||
* The exact rounding details will be resolved at runtime based on the currency unit specified in the
|
||||
* NumberFormatter chain. To round according to the rules for one currency while displaying the symbol for another
|
||||
* currency, the withCurrency() method can be called on the return value of this method.
|
||||
*
|
||||
* @param currencyUsage
|
||||
* Either STANDARD (for digital transactions) or CASH (for transactions where the rounding increment may
|
||||
* be limited by the available denominations of cash or coins).
|
||||
* @return A CurrencyRounder for chaining or passing to the NumberFormatter rounding() setter.
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public static CurrencyRounder currency(CurrencyUsage currencyUsage) {
|
||||
if (currencyUsage != null) {
|
||||
return constructCurrency(currencyUsage);
|
||||
|
@ -186,15 +306,14 @@ public abstract class Rounder implements Cloneable {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link java.math.RoundingMode} to use when picking the direction to round (up or down).
|
||||
*
|
||||
* <p>
|
||||
* Common values include {@link RoundingMode#HALF_EVEN}, {@link RoundingMode#HALF_UP}, and
|
||||
* {@link RoundingMode#CEILING}. The default is HALF_EVEN.
|
||||
* Sets the {@link java.math.RoundingMode} to use when picking the direction to round (up or down). Common values
|
||||
* include HALF_EVEN, HALF_UP, and FLOOR. The default is HALF_EVEN.
|
||||
*
|
||||
* @param roundingMode
|
||||
* The RoundingMode to use.
|
||||
* @return An immutable object for chaining.
|
||||
* @return A Rounder for chaining.
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public Rounder withMode(RoundingMode roundingMode) {
|
||||
return withMode(RoundingUtils.mathContextUnlimited(roundingMode));
|
||||
|
@ -216,6 +335,11 @@ public abstract class Rounder implements Cloneable {
|
|||
return other;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated This API is ICU internal only.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public Object clone() {
|
||||
try {
|
||||
|
@ -237,23 +361,24 @@ public abstract class Rounder implements Cloneable {
|
|||
// PACKAGE-PRIVATE APIS //
|
||||
//////////////////////////
|
||||
|
||||
private static final InfiniteRounderImpl NONE = new InfiniteRounderImpl();
|
||||
static final InfiniteRounderImpl NONE = new InfiniteRounderImpl();
|
||||
|
||||
private static final FractionRounderImpl FIXED_FRAC_0 = new FractionRounderImpl(0, 0);
|
||||
private static final FractionRounderImpl FIXED_FRAC_2 = new FractionRounderImpl(2, 2);
|
||||
static final FractionRounderImpl FIXED_FRAC_0 = new FractionRounderImpl(0, 0);
|
||||
static final FractionRounderImpl FIXED_FRAC_2 = new FractionRounderImpl(2, 2);
|
||||
static final FractionRounderImpl MAX_FRAC_6 = new FractionRounderImpl(0, 6);
|
||||
|
||||
private static final SignificantRounderImpl FIXED_SIG_2 = new SignificantRounderImpl(2, 2);
|
||||
private static final SignificantRounderImpl FIXED_SIG_3 = new SignificantRounderImpl(3, 3);
|
||||
private static final SignificantRounderImpl RANGE_SIG_2_3 = new SignificantRounderImpl(2, 3);
|
||||
static final SignificantRounderImpl FIXED_SIG_2 = new SignificantRounderImpl(2, 2);
|
||||
static final SignificantRounderImpl FIXED_SIG_3 = new SignificantRounderImpl(3, 3);
|
||||
static final SignificantRounderImpl RANGE_SIG_2_3 = new SignificantRounderImpl(2, 3);
|
||||
|
||||
/* package-private */ static final FracSigRounderImpl COMPACT_STRATEGY = new FracSigRounderImpl(0, 0, 2, -1);
|
||||
static final FracSigRounderImpl COMPACT_STRATEGY = new FracSigRounderImpl(0, 0, 2, -1);
|
||||
|
||||
private static final IncrementRounderImpl NICKEL = new IncrementRounderImpl(BigDecimal.valueOf(0.5));
|
||||
static final IncrementRounderImpl NICKEL = new IncrementRounderImpl(BigDecimal.valueOf(0.05));
|
||||
|
||||
private static final CurrencyRounderImpl MONETARY_STANDARD = new CurrencyRounderImpl(CurrencyUsage.STANDARD);
|
||||
private static final CurrencyRounderImpl MONETARY_CASH = new CurrencyRounderImpl(CurrencyUsage.CASH);
|
||||
static final CurrencyRounderImpl MONETARY_STANDARD = new CurrencyRounderImpl(CurrencyUsage.STANDARD);
|
||||
static final CurrencyRounderImpl MONETARY_CASH = new CurrencyRounderImpl(CurrencyUsage.CASH);
|
||||
|
||||
private static final PassThroughRounderImpl PASS_THROUGH = new PassThroughRounderImpl();
|
||||
static final PassThroughRounderImpl PASS_THROUGH = new PassThroughRounderImpl();
|
||||
|
||||
static Rounder constructInfinite() {
|
||||
return NONE;
|
||||
|
@ -264,6 +389,8 @@ public abstract class Rounder implements Cloneable {
|
|||
return FIXED_FRAC_0;
|
||||
} else if (minFrac == 2 && maxFrac == 2) {
|
||||
return FIXED_FRAC_2;
|
||||
} else if (minFrac == 0 && maxFrac == 6) {
|
||||
return MAX_FRAC_6;
|
||||
} else {
|
||||
return new FractionRounderImpl(minFrac, maxFrac);
|
||||
}
|
||||
|
@ -293,7 +420,8 @@ public abstract class Rounder implements Cloneable {
|
|||
}
|
||||
|
||||
static Rounder constructIncrement(BigDecimal increment) {
|
||||
if (increment.compareTo(NICKEL.increment) == 0) {
|
||||
// NOTE: .equals() is what we want, not .compareTo()
|
||||
if (increment.equals(NICKEL.increment)) {
|
||||
return NICKEL;
|
||||
} else {
|
||||
return new IncrementRounderImpl(increment);
|
||||
|
@ -331,17 +459,15 @@ public abstract class Rounder implements Cloneable {
|
|||
* Returns a valid working Rounder. If the Rounder is a CurrencyRounder, applies the given currency. Otherwise,
|
||||
* simply passes through the argument.
|
||||
*
|
||||
* @param rounder
|
||||
* The input object.
|
||||
* @param currency
|
||||
* A currency object to use in case the input object needs it.
|
||||
* @return A Rounder object ready for use.
|
||||
*/
|
||||
static Rounder normalizeType(Rounder rounder, Currency currency) {
|
||||
if (rounder instanceof CurrencyRounder) {
|
||||
return ((CurrencyRounder) rounder).withCurrency(currency);
|
||||
Rounder withLocaleData(Currency currency) {
|
||||
if (this instanceof CurrencyRounder) {
|
||||
return ((CurrencyRounder) this).withCurrency(currency);
|
||||
} else {
|
||||
return rounder;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +1,28 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package newapi;
|
||||
package com.ibm.icu.number;
|
||||
|
||||
import com.ibm.icu.impl.number.DecimalQuantity;
|
||||
import com.ibm.icu.impl.number.MicroProps;
|
||||
import com.ibm.icu.impl.number.MicroPropsGenerator;
|
||||
import com.ibm.icu.impl.number.Modifier;
|
||||
import com.ibm.icu.impl.number.MultiplierProducer;
|
||||
import com.ibm.icu.impl.number.NumberStringBuilder;
|
||||
import com.ibm.icu.impl.number.RoundingUtils;
|
||||
import com.ibm.icu.number.NumberFormatter.SignDisplay;
|
||||
import com.ibm.icu.number.Rounder.SignificantRounderImpl;
|
||||
import com.ibm.icu.text.DecimalFormatSymbols;
|
||||
import com.ibm.icu.text.NumberFormat;
|
||||
|
||||
import newapi.NumberFormatter.SignDisplay;
|
||||
import newapi.Rounder.SignificantRounderImpl;
|
||||
import newapi.impl.MicroProps;
|
||||
import newapi.impl.MicroPropsGenerator;
|
||||
import newapi.impl.MultiplierProducer;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
/**
|
||||
* A class that defines the scientific notation style to be used when formatting numbers in NumberFormatter.
|
||||
*
|
||||
* <p>
|
||||
* To create a ScientificNotation, use one of the factory methods in {@link Notation}.
|
||||
*
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public class ScientificNotation extends Notation implements Cloneable {
|
||||
|
||||
int engineeringInterval;
|
||||
|
@ -30,22 +38,56 @@ public class ScientificNotation extends Notation implements Cloneable {
|
|||
this.exponentSignDisplay = exponentSignDisplay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum number of digits to show in the exponent of scientific notation, padding with zeros if
|
||||
* necessary. Useful for fixed-width display.
|
||||
*
|
||||
* <p>
|
||||
* For example, with minExponentDigits=2, the number 123 will be printed as "1.23E02" in <em>en-US</em> instead of
|
||||
* the default "1.23E2".
|
||||
*
|
||||
* @param minExponentDigits
|
||||
* The minimum number of digits to show in the exponent.
|
||||
* @return A ScientificNotation, for chaining.
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public ScientificNotation withMinExponentDigits(int minExponentDigits) {
|
||||
if (minExponentDigits >= 0 && minExponentDigits < Rounder.MAX_VALUE) {
|
||||
if (minExponentDigits >= 0 && minExponentDigits < RoundingUtils.MAX_INT_FRAC_SIG) {
|
||||
ScientificNotation other = (ScientificNotation) this.clone();
|
||||
other.minExponentDigits = minExponentDigits;
|
||||
return other;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Integer digits must be between 0 and " + Rounder.MAX_VALUE);
|
||||
throw new IllegalArgumentException(
|
||||
"Integer digits must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to show the sign on positive and negative exponents in scientific notation. The default is AUTO,
|
||||
* showing the minus sign but not the plus sign.
|
||||
*
|
||||
* <p>
|
||||
* For example, with exponentSignDisplay=ALWAYS, the number 123 will be printed as "1.23E+2" in <em>en-US</em>
|
||||
* instead of the default "1.23E2".
|
||||
*
|
||||
* @param exponentSignDisplay
|
||||
* The strategy for displaying the sign in the exponent.
|
||||
* @return A ScientificNotation, for chaining.
|
||||
* @draft ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public ScientificNotation withExponentSignDisplay(SignDisplay exponentSignDisplay) {
|
||||
ScientificNotation other = (ScientificNotation) this.clone();
|
||||
other.exponentSignDisplay = exponentSignDisplay;
|
||||
return other;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated This API is ICU internal only.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public Object clone() {
|
||||
try {
|
||||
|
@ -183,7 +225,7 @@ public class ScientificNotation extends Notation implements Cloneable {
|
|||
i += output.insert(i, symbols.getExponentSeparator(), NumberFormat.Field.EXPONENT_SYMBOL);
|
||||
if (exponent < 0 && notation.exponentSignDisplay != SignDisplay.NEVER) {
|
||||
i += output.insert(i, symbols.getMinusSignString(), NumberFormat.Field.EXPONENT_SIGN);
|
||||
} else if (notation.exponentSignDisplay == SignDisplay.ALWAYS) {
|
||||
} else if (exponent >= 0 && notation.exponentSignDisplay == SignDisplay.ALWAYS) {
|
||||
i += output.insert(i, symbols.getPlusSignString(), NumberFormat.Field.EXPONENT_SIGN);
|
||||
}
|
||||
// Append the exponent digits (using a simple inline algorithm)
|
|
@ -1,6 +1,6 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package newapi;
|
||||
package com.ibm.icu.number;
|
||||
|
||||
public class SimpleNotation extends Notation {
|
||||
/* package-private */ SimpleNotation() {
|
|
@ -1,6 +1,6 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package newapi;
|
||||
package com.ibm.icu.number;
|
||||
|
||||
import java.util.Locale;
|
||||
|
|
@ -15,12 +15,16 @@ import java.text.ParsePosition;
|
|||
|
||||
import com.ibm.icu.impl.number.AffixUtils;
|
||||
import com.ibm.icu.impl.number.DecimalFormatProperties;
|
||||
import com.ibm.icu.impl.number.Padder.PadPosition;
|
||||
import com.ibm.icu.impl.number.Parse;
|
||||
import com.ibm.icu.impl.number.PatternStringParser;
|
||||
import com.ibm.icu.impl.number.PatternStringUtils;
|
||||
import com.ibm.icu.lang.UCharacter;
|
||||
import com.ibm.icu.math.BigDecimal;
|
||||
import com.ibm.icu.math.MathContext;
|
||||
import com.ibm.icu.number.FormattedNumber;
|
||||
import com.ibm.icu.number.LocalizedNumberFormatter;
|
||||
import com.ibm.icu.number.NumberFormatter;
|
||||
import com.ibm.icu.text.PluralRules.IFixedDecimal;
|
||||
import com.ibm.icu.util.Currency;
|
||||
import com.ibm.icu.util.Currency.CurrencyUsage;
|
||||
|
@ -28,11 +32,6 @@ import com.ibm.icu.util.CurrencyAmount;
|
|||
import com.ibm.icu.util.ULocale;
|
||||
import com.ibm.icu.util.ULocale.Category;
|
||||
|
||||
import newapi.FormattedNumber;
|
||||
import newapi.LocalizedNumberFormatter;
|
||||
import newapi.NumberFormatter;
|
||||
import newapi.impl.Padder.PadPosition;
|
||||
|
||||
/**
|
||||
* {@icuenhanced java.text.DecimalFormat}.{@icu _usage_} <code>DecimalFormat</code> is the primary
|
||||
* concrete subclass of {@link NumberFormat}. It has a variety of features designed to make it
|
||||
|
|
|
@ -1490,6 +1490,22 @@ public abstract class NumberFormat extends UFormat {
|
|||
*/
|
||||
@Deprecated
|
||||
public static String getPatternForStyle(ULocale forLocale, int choice) {
|
||||
NumberingSystem ns = NumberingSystem.getInstance(forLocale);
|
||||
String nsName = ns.getName();
|
||||
return getPatternForStyleAndNumberingSystem(forLocale, nsName, choice);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the pattern for the provided locale, numbering system, and choice.
|
||||
* @param forLocale the locale of the data.
|
||||
* @param nsName The name of the numbering system, like "latn".
|
||||
* @param choice the pattern format.
|
||||
* @return the pattern
|
||||
* @internal
|
||||
* @deprecated This API is ICU internal only.
|
||||
*/
|
||||
@Deprecated
|
||||
public static String getPatternForStyleAndNumberingSystem(ULocale forLocale, String nsName, int choice) {
|
||||
/* for ISOCURRENCYSTYLE and PLURALCURRENCYSTYLE,
|
||||
* the pattern is the same as the pattern of CURRENCYSTYLE
|
||||
* but by replacing the single currency sign with
|
||||
|
@ -1529,10 +1545,9 @@ public abstract class NumberFormat extends UFormat {
|
|||
|
||||
ICUResourceBundle rb = (ICUResourceBundle)UResourceBundle.
|
||||
getBundleInstance(ICUData.ICU_BASE_NAME, forLocale);
|
||||
NumberingSystem ns = NumberingSystem.getInstance(forLocale);
|
||||
|
||||
String result = rb.findStringWithFallback(
|
||||
"NumberElements/" + ns.getName() + "/patterns/" + patternKey);
|
||||
"NumberElements/" + nsName + "/patterns/" + patternKey);
|
||||
if (result == null) {
|
||||
result = rb.getStringWithFallback("NumberElements/latn/patterns/" + patternKey);
|
||||
}
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package newapi;
|
||||
|
||||
import com.ibm.icu.text.CompactDecimalFormat.CompactStyle;
|
||||
|
||||
import newapi.NumberFormatter.SignDisplay;
|
||||
|
||||
public class Notation {
|
||||
|
||||
// FIXME: Support engineering intervals other than 3?
|
||||
private static final ScientificNotation SCIENTIFIC = new ScientificNotation(1, false, 1, SignDisplay.AUTO);
|
||||
private static final ScientificNotation ENGINEERING = new ScientificNotation(3, false, 1, SignDisplay.AUTO);
|
||||
private static final CompactNotation COMPACT_SHORT = new CompactNotation(CompactStyle.SHORT);
|
||||
private static final CompactNotation COMPACT_LONG = new CompactNotation(CompactStyle.LONG);
|
||||
private static final SimpleNotation SIMPLE = new SimpleNotation();
|
||||
|
||||
/* package-private */ Notation() {
|
||||
}
|
||||
|
||||
public static ScientificNotation scientific() {
|
||||
return SCIENTIFIC;
|
||||
}
|
||||
|
||||
public static ScientificNotation engineering() {
|
||||
return ENGINEERING;
|
||||
}
|
||||
|
||||
public static CompactNotation compactShort() {
|
||||
return COMPACT_SHORT;
|
||||
}
|
||||
|
||||
public static CompactNotation compactLong() {
|
||||
return COMPACT_LONG;
|
||||
}
|
||||
|
||||
public static SimpleNotation simple() {
|
||||
return SIMPLE;
|
||||
}
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package newapi;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import com.ibm.icu.impl.number.DecimalFormatProperties;
|
||||
import com.ibm.icu.text.DecimalFormatSymbols;
|
||||
import com.ibm.icu.util.ULocale;
|
||||
|
||||
import newapi.impl.MacroProps;
|
||||
|
||||
public final class NumberFormatter {
|
||||
|
||||
private static final UnlocalizedNumberFormatter BASE = new UnlocalizedNumberFormatter();
|
||||
|
||||
public static enum UnitWidth {
|
||||
NARROW, // ¤¤¤¤¤ or narrow measure unit
|
||||
SHORT, // ¤ or short measure unit (DEFAULT)
|
||||
ISO_CODE, // ¤¤; undefined for measure unit
|
||||
FULL_NAME, // ¤¤¤ or wide unit
|
||||
HIDDEN, // no unit is displayed, but other unit effects are obeyed (like currency rounding)
|
||||
// TODO: For hidden, what to do if currency symbol appears in the middle, as in Portugal ?
|
||||
}
|
||||
|
||||
public static enum DecimalMarkDisplay {
|
||||
AUTO, ALWAYS,
|
||||
}
|
||||
|
||||
public static enum SignDisplay {
|
||||
AUTO, ALWAYS, NEVER, ACCOUNTING, ACCOUNTING_ALWAYS,
|
||||
}
|
||||
|
||||
/**
|
||||
* Use a default threshold of 3. This means that the third time .format() is called, the data structures get built
|
||||
* using the "safe" code path. The first two calls to .format() will trigger the unsafe code path.
|
||||
*/
|
||||
static final long DEFAULT_THRESHOLD = 3;
|
||||
|
||||
public static UnlocalizedNumberFormatter with() {
|
||||
return BASE;
|
||||
}
|
||||
|
||||
public static LocalizedNumberFormatter withLocale(Locale locale) {
|
||||
return BASE.locale(locale);
|
||||
}
|
||||
|
||||
public static LocalizedNumberFormatter withLocale(ULocale locale) {
|
||||
return BASE.locale(locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated ICU 60 This API is ICU internal only.
|
||||
*/
|
||||
@Deprecated
|
||||
public static UnlocalizedNumberFormatter fromDecimalFormat(DecimalFormatProperties properties,
|
||||
DecimalFormatSymbols symbols, DecimalFormatProperties exportedProperties) {
|
||||
MacroProps macros = NumberPropertyMapper.oldToNew(properties, symbols, exportedProperties);
|
||||
return NumberFormatter.with().macros(macros);
|
||||
}
|
||||
}
|
|
@ -1,586 +0,0 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package newapi;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
import com.ibm.icu.text.CompactDecimalFormat.CompactStyle;
|
||||
import com.ibm.icu.text.DecimalFormatSymbols;
|
||||
import com.ibm.icu.text.NumberingSystem;
|
||||
import com.ibm.icu.util.Currency;
|
||||
import com.ibm.icu.util.Currency.CurrencyUsage;
|
||||
import com.ibm.icu.util.MeasureUnit;
|
||||
import com.ibm.icu.util.NoUnit;
|
||||
|
||||
import newapi.NumberFormatter.DecimalMarkDisplay;
|
||||
import newapi.NumberFormatter.SignDisplay;
|
||||
import newapi.NumberFormatter.UnitWidth;
|
||||
import newapi.Rounder.CurrencyRounderImpl;
|
||||
import newapi.Rounder.FracSigRounderImpl;
|
||||
import newapi.Rounder.FractionRounderImpl;
|
||||
import newapi.Rounder.IncrementRounderImpl;
|
||||
import newapi.Rounder.InfiniteRounderImpl;
|
||||
import newapi.Rounder.SignificantRounderImpl;
|
||||
import newapi.impl.MacroProps;
|
||||
|
||||
final class SkeletonBuilder {
|
||||
|
||||
public static String macrosToSkeleton(MacroProps macros) {
|
||||
// Print out the values in their canonical order.
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (macros.notation != null) {
|
||||
// sb.append("notation=");
|
||||
notationToSkeleton(macros.notation, sb);
|
||||
sb.append(' ');
|
||||
}
|
||||
if (macros.unit != null) {
|
||||
// sb.append("unit=");
|
||||
unitToSkeleton(macros.unit, sb);
|
||||
sb.append(' ');
|
||||
}
|
||||
if (macros.rounder != null) {
|
||||
// sb.append("rounding=");
|
||||
rounderToSkeleton(macros.rounder, sb);
|
||||
sb.append(' ');
|
||||
}
|
||||
if (macros.grouper != null) {
|
||||
sb.append("grouping=");
|
||||
grouperToSkeleton(macros.grouper, sb);
|
||||
sb.append(' ');
|
||||
}
|
||||
// if (macros.padder != null) {
|
||||
// sb.append("padding=");
|
||||
// paddingToSkeleton(macros.padder, sb);
|
||||
// sb.append(' ');
|
||||
// }
|
||||
if (macros.integerWidth != null) {
|
||||
sb.append("integer-width=");
|
||||
integerWidthToSkeleton(macros.integerWidth, sb);
|
||||
sb.append(' ');
|
||||
}
|
||||
if (macros.symbols != null) {
|
||||
sb.append("symbols=");
|
||||
symbolsToSkeleton(macros.symbols, sb);
|
||||
sb.append(' ');
|
||||
}
|
||||
if (macros.unitWidth != null) {
|
||||
sb.append("unit-width=");
|
||||
unitWidthToSkeleton(macros.unitWidth, sb);
|
||||
sb.append(' ');
|
||||
}
|
||||
if (macros.sign != null) {
|
||||
sb.append("sign=");
|
||||
signToSkeleton(macros.sign, sb);
|
||||
sb.append(' ');
|
||||
}
|
||||
if (macros.decimal != null) {
|
||||
sb.append("decimal=");
|
||||
decimalToSkeleton(macros.decimal, sb);
|
||||
sb.append(' ');
|
||||
}
|
||||
if (sb.length() > 0) {
|
||||
// Remove the trailing space
|
||||
sb.setLength(sb.length() - 1);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static MacroProps skeletonToMacros(String skeleton) {
|
||||
MacroProps macros = new MacroProps();
|
||||
for (int offset = 0; offset < skeleton.length();) {
|
||||
char c = skeleton.charAt(offset);
|
||||
switch (c) {
|
||||
case ' ':
|
||||
offset++;
|
||||
break;
|
||||
case 'E':
|
||||
case 'C':
|
||||
case 'I':
|
||||
offset += skeletonToNotation(skeleton, offset, macros);
|
||||
break;
|
||||
case '%':
|
||||
case 'B':
|
||||
case '$':
|
||||
case 'U':
|
||||
offset += skeletonToUnit(skeleton, offset, macros);
|
||||
break;
|
||||
case 'F':
|
||||
case 'S':
|
||||
case 'M':
|
||||
case 'G':
|
||||
case 'Y':
|
||||
offset += skeletonToRounding(skeleton, offset, macros);
|
||||
break;
|
||||
default:
|
||||
if (skeleton.regionMatches(offset, "notation=", 0, 9)) {
|
||||
offset += 9;
|
||||
offset += skeletonToNotation(skeleton, offset, macros);
|
||||
} else if (skeleton.regionMatches(offset, "unit=", 0, 5)) {
|
||||
offset += 5;
|
||||
offset += skeletonToUnit(skeleton, offset, macros);
|
||||
} else if (skeleton.regionMatches(offset, "rounding=", 0, 9)) {
|
||||
offset += 9;
|
||||
offset += skeletonToRounding(skeleton, offset, macros);
|
||||
} else if (skeleton.regionMatches(offset, "grouping=", 0, 9)) {
|
||||
offset += 9;
|
||||
offset += skeletonToGrouping(skeleton, offset, macros);
|
||||
// } else if (skeleton.regionMatches(offset, "padding=", 0, 9)) {
|
||||
// offset += 8;
|
||||
// offset += skeletonToPadding(skeleton, offset, macros);
|
||||
} else if (skeleton.regionMatches(offset, "integer-width=", 0, 9)) {
|
||||
offset += 14;
|
||||
offset += skeletonToIntegerWidth(skeleton, offset, macros);
|
||||
} else if (skeleton.regionMatches(offset, "symbols=", 0, 9)) {
|
||||
offset += 8;
|
||||
offset += skeletonToSymbols(skeleton, offset, macros);
|
||||
} else if (skeleton.regionMatches(offset, "unit-width=", 0, 9)) {
|
||||
offset += 11;
|
||||
offset += skeletonToUnitWidth(skeleton, offset, macros);
|
||||
} else if (skeleton.regionMatches(offset, "sign=", 0, 9)) {
|
||||
offset += 5;
|
||||
offset += skeletonToSign(skeleton, offset, macros);
|
||||
} else if (skeleton.regionMatches(offset, "decimal=", 0, 9)) {
|
||||
offset += 8;
|
||||
offset += skeletonToDecimal(skeleton, offset, macros);
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Unexpected token at offset " + offset + " in skeleton string: " + c);
|
||||
}
|
||||
}
|
||||
}
|
||||
return macros;
|
||||
}
|
||||
|
||||
private static void notationToSkeleton(Notation value, StringBuilder sb) {
|
||||
if (value instanceof ScientificNotation) {
|
||||
ScientificNotation notation = (ScientificNotation) value;
|
||||
sb.append('E');
|
||||
if (notation.engineeringInterval != 1) {
|
||||
sb.append(notation.engineeringInterval);
|
||||
}
|
||||
if (notation.exponentSignDisplay == SignDisplay.ALWAYS) {
|
||||
sb.append('+');
|
||||
} else if (notation.exponentSignDisplay == SignDisplay.NEVER) {
|
||||
sb.append('!');
|
||||
} else {
|
||||
assert notation.exponentSignDisplay == SignDisplay.AUTO;
|
||||
}
|
||||
if (notation.minExponentDigits != 1) {
|
||||
for (int i = 0; i < notation.minExponentDigits; i++) {
|
||||
sb.append('0');
|
||||
}
|
||||
}
|
||||
} else if (value instanceof CompactNotation) {
|
||||
CompactNotation notation = (CompactNotation) value;
|
||||
if (notation.compactStyle == CompactStyle.SHORT) {
|
||||
sb.append('C');
|
||||
} else {
|
||||
// FIXME: CCC or CCCC instead?
|
||||
sb.append("CC");
|
||||
}
|
||||
} else {
|
||||
assert value instanceof SimpleNotation;
|
||||
sb.append('I');
|
||||
}
|
||||
}
|
||||
|
||||
private static int skeletonToNotation(String skeleton, int offset, MacroProps output) {
|
||||
int originalOffset = offset;
|
||||
char c0 = skeleton.charAt(offset++);
|
||||
Notation result = null;
|
||||
if (c0 == 'E') {
|
||||
int engineering = 1;
|
||||
SignDisplay sign = SignDisplay.AUTO;
|
||||
int minExponentDigits = 0;
|
||||
char c = safeCharAt(skeleton, offset++);
|
||||
if (c >= '1' && c <= '9') {
|
||||
engineering = c - '0';
|
||||
c = safeCharAt(skeleton, offset++);
|
||||
}
|
||||
if (c == '+') {
|
||||
sign = SignDisplay.ALWAYS;
|
||||
c = safeCharAt(skeleton, offset++);
|
||||
}
|
||||
if (c == '!') {
|
||||
sign = SignDisplay.NEVER;
|
||||
c = safeCharAt(skeleton, offset++);
|
||||
}
|
||||
while (c == '0') {
|
||||
minExponentDigits++;
|
||||
c = safeCharAt(skeleton, offset++);
|
||||
}
|
||||
minExponentDigits = Math.max(1, minExponentDigits);
|
||||
result = new ScientificNotation(engineering, false, minExponentDigits, sign);
|
||||
} else if (c0 == 'C') {
|
||||
char c = safeCharAt(skeleton, offset++);
|
||||
if (c == 'C') {
|
||||
result = Notation.compactLong();
|
||||
} else {
|
||||
result = Notation.compactShort();
|
||||
}
|
||||
} else if (c0 == 'I') {
|
||||
result = Notation.simple();
|
||||
}
|
||||
output.notation = result;
|
||||
return offset - originalOffset;
|
||||
}
|
||||
|
||||
private static void unitToSkeleton(MeasureUnit value, StringBuilder sb) {
|
||||
if (value.getType().equals("none")) {
|
||||
if (value.getSubtype().equals("percent")) {
|
||||
sb.append('%');
|
||||
} else if (value.getSubtype().equals("permille")) {
|
||||
sb.append("%%");
|
||||
} else {
|
||||
assert value.getSubtype().equals("base");
|
||||
sb.append('B');
|
||||
}
|
||||
} else if (value.getType().equals("currency")) {
|
||||
sb.append('$');
|
||||
sb.append(value.getSubtype());
|
||||
} else {
|
||||
sb.append("U:");
|
||||
sb.append(value.getType());
|
||||
sb.append(':');
|
||||
sb.append(value.getSubtype());
|
||||
}
|
||||
}
|
||||
|
||||
private static int skeletonToUnit(String skeleton, int offset, MacroProps output) {
|
||||
int originalOffset = offset;
|
||||
char c0 = skeleton.charAt(offset++);
|
||||
MeasureUnit result = null;
|
||||
if (c0 == '%') {
|
||||
char c = safeCharAt(skeleton, offset++);
|
||||
if (c == '%') {
|
||||
result = NoUnit.PERCENT;
|
||||
} else {
|
||||
result = NoUnit.PERMILLE;
|
||||
}
|
||||
} else if (c0 == 'B') {
|
||||
result = NoUnit.BASE;
|
||||
} else if (c0 == '$') {
|
||||
String currencyCode = skeleton.substring(offset, offset + 3);
|
||||
offset += 3;
|
||||
result = Currency.getInstance(currencyCode);
|
||||
} else if (c0 == 'U') {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
offset += consumeUntil(skeleton, offset, ':', sb);
|
||||
String type = sb.toString();
|
||||
sb.setLength(0);
|
||||
offset += consumeUntil(skeleton, offset, ' ', sb);
|
||||
String subtype = sb.toString();
|
||||
for (MeasureUnit candidate : MeasureUnit.getAvailable(type)) {
|
||||
if (candidate.getSubtype().equals(subtype)) {
|
||||
result = candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
output.unit = result;
|
||||
return offset - originalOffset;
|
||||
}
|
||||
|
||||
private static void rounderToSkeleton(Rounder value, StringBuilder sb) {
|
||||
if (!(value instanceof Rounder)) {
|
||||
// FIXME: Throw an exception here instead?
|
||||
return;
|
||||
}
|
||||
MathContext mathContext;
|
||||
if (value instanceof FractionRounderImpl) {
|
||||
FractionRounderImpl rounder = (FractionRounderImpl) value;
|
||||
sb.append('F');
|
||||
minMaxToSkeletonHelper(rounder.minFrac, rounder.maxFrac, sb);
|
||||
mathContext = rounder.mathContext;
|
||||
} else if (value instanceof SignificantRounderImpl) {
|
||||
SignificantRounderImpl rounder = (SignificantRounderImpl) value;
|
||||
sb.append('S');
|
||||
minMaxToSkeletonHelper(rounder.minSig, rounder.maxSig, sb);
|
||||
mathContext = rounder.mathContext;
|
||||
} else if (value instanceof FracSigRounderImpl) {
|
||||
FracSigRounderImpl rounder = (FracSigRounderImpl) value;
|
||||
sb.append('F');
|
||||
minMaxToSkeletonHelper(rounder.minFrac, rounder.maxFrac, sb);
|
||||
if (rounder.minSig != -1) {
|
||||
sb.append('>');
|
||||
sb.append(rounder.minSig);
|
||||
} else {
|
||||
sb.append('<');
|
||||
sb.append(rounder.maxSig);
|
||||
}
|
||||
mathContext = rounder.mathContext;
|
||||
} else if (value instanceof IncrementRounderImpl) {
|
||||
IncrementRounderImpl rounder = (IncrementRounderImpl) value;
|
||||
sb.append('M');
|
||||
sb.append(rounder.increment.toString());
|
||||
mathContext = rounder.mathContext;
|
||||
} else if (value instanceof CurrencyRounderImpl) {
|
||||
CurrencyRounderImpl rounder = (CurrencyRounderImpl) value;
|
||||
sb.append('G');
|
||||
sb.append(rounder.usage.name());
|
||||
mathContext = rounder.mathContext;
|
||||
} else {
|
||||
InfiniteRounderImpl rounder = (InfiniteRounderImpl) value;
|
||||
sb.append('Y');
|
||||
mathContext = rounder.mathContext;
|
||||
}
|
||||
// RoundingMode
|
||||
RoundingMode roundingMode = mathContext.getRoundingMode();
|
||||
if (roundingMode != RoundingMode.HALF_EVEN) {
|
||||
sb.append(';');
|
||||
sb.append(roundingMode.name());
|
||||
}
|
||||
}
|
||||
|
||||
private static void minMaxToSkeletonHelper(int minFrac, int maxFrac, StringBuilder sb) {
|
||||
if (minFrac == maxFrac) {
|
||||
sb.append(minFrac);
|
||||
} else {
|
||||
boolean showMaxFrac = (maxFrac >= 0 && maxFrac < Integer.MAX_VALUE);
|
||||
if (minFrac > 0 || !showMaxFrac) {
|
||||
sb.append(minFrac);
|
||||
}
|
||||
sb.append('-');
|
||||
if (showMaxFrac) {
|
||||
sb.append(maxFrac);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int skeletonToRounding(String skeleton, int offset, MacroProps output) {
|
||||
int originalOffset = offset;
|
||||
char c0 = skeleton.charAt(offset++);
|
||||
Rounder result = null;
|
||||
if (c0 == 'F') {
|
||||
int[] minMax = new int[2];
|
||||
offset += skeletonToMinMaxHelper(skeleton, offset, minMax);
|
||||
FractionRounder temp = Rounder.constructFraction(minMax[0], minMax[1]);
|
||||
char c1 = skeleton.charAt(offset++);
|
||||
if (c1 == '<') {
|
||||
char c2 = skeleton.charAt(offset++);
|
||||
result = temp.withMaxDigits(c2 - '0');
|
||||
} else if (c1 == '>') {
|
||||
char c2 = skeleton.charAt(offset++);
|
||||
result = temp.withMinDigits(c2 - '0');
|
||||
} else {
|
||||
result = temp;
|
||||
}
|
||||
} else if (c0 == 'S') {
|
||||
int[] minMax = new int[2];
|
||||
offset += skeletonToMinMaxHelper(skeleton, offset, minMax);
|
||||
result = Rounder.constructSignificant(minMax[0], minMax[1]);
|
||||
} else if (c0 == 'M') {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
offset += consumeUntil(skeleton, offset, ' ', sb);
|
||||
BigDecimal increment = new BigDecimal(sb.toString());
|
||||
result = Rounder.constructIncrement(increment);
|
||||
} else if (c0 == 'G') {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
offset += consumeUntil(skeleton, offset, ' ', sb);
|
||||
CurrencyUsage usage = Enum.valueOf(CurrencyUsage.class, sb.toString());
|
||||
result = Rounder.constructCurrency(usage);
|
||||
} else if (c0 == 'Y') {
|
||||
result = Rounder.constructInfinite();
|
||||
}
|
||||
output.rounder = result;
|
||||
return offset - originalOffset;
|
||||
}
|
||||
|
||||
private static int skeletonToMinMaxHelper(String skeleton, int offset, int[] output) {
|
||||
int originalOffset = offset;
|
||||
char c0 = safeCharAt(skeleton, offset++);
|
||||
char c1 = safeCharAt(skeleton, offset++);
|
||||
// TODO: This algorithm breaks if the number is more than 1 char wide.
|
||||
if (c1 == '-') {
|
||||
output[0] = c0 - '0';
|
||||
char c2 = safeCharAt(skeleton, offset++);
|
||||
if (c2 == ' ') {
|
||||
output[1] = Integer.MAX_VALUE;
|
||||
} else {
|
||||
output[1] = c2 - '0';
|
||||
}
|
||||
} else if ('0' <= c1 && c1 <= '9') {
|
||||
output[0] = 0;
|
||||
output[1] = c1 - '0';
|
||||
} else {
|
||||
offset--;
|
||||
output[0] = c0 - '0';
|
||||
output[1] = c0 - '0';
|
||||
}
|
||||
return offset - originalOffset;
|
||||
}
|
||||
|
||||
private static void grouperToSkeleton(Grouper value, StringBuilder sb) {
|
||||
if (value.equals(Grouper.defaults())) {
|
||||
sb.append("defaults");
|
||||
} else if (value.equals(Grouper.min2())) {
|
||||
sb.append("min2");
|
||||
} else if (value.equals(Grouper.none())) {
|
||||
sb.append("none");
|
||||
} else {
|
||||
// Not supported in skeleton string
|
||||
sb.append("defaults");
|
||||
}
|
||||
}
|
||||
|
||||
private static int skeletonToGrouping(String skeleton, int offset, MacroProps output) {
|
||||
int originalOffset = offset;
|
||||
char c0 = skeleton.charAt(offset++);
|
||||
Grouper result = null;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
offset += consumeUntil(skeleton, --offset, ' ', sb);
|
||||
String name = sb.toString();
|
||||
if (name.equals("defaults")) {
|
||||
result = Grouper.defaults();
|
||||
} else if (name.equals("min2")) {
|
||||
result = Grouper.min2();
|
||||
} else if (name.equals("none")) {
|
||||
result = Grouper.none();
|
||||
}
|
||||
output.grouper = result;
|
||||
return offset - originalOffset;
|
||||
}
|
||||
|
||||
// private static void paddingToSkeleton(Padder value, StringBuilder sb) {
|
||||
// PaddingImpl padding = (PaddingImpl) value;
|
||||
// if (padding == Padder.NONE) {
|
||||
// sb.append("NONE");
|
||||
// return;
|
||||
// }
|
||||
// sb.append(padding.targetWidth);
|
||||
// sb.append(':');
|
||||
// sb.append(padding.position.name());
|
||||
// sb.append(':');
|
||||
// if (!padding.paddingString.equals(" ")) {
|
||||
// sb.append(padding.paddingString);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private static int skeletonToPadding(String skeleton, int offset, MacroProps output) {
|
||||
// int originalOffset = offset;
|
||||
// char c0 = skeleton.charAt(offset++);
|
||||
// if (c0 == 'N') {
|
||||
// offset += consumeUntil(skeleton, --offset, ' ', null);
|
||||
// } else if ('0' <= c0 && c0 <= '9') {
|
||||
// long intResult = consumeInt(skeleton, --offset);
|
||||
// offset += intResult & 0xffffffff;
|
||||
// int width = (int) (intResult >>> 32);
|
||||
// char c1 = safeCharAt(skeleton, offset++);
|
||||
// if (c1 != ':') {
|
||||
// return offset - originalOffset - 1;
|
||||
// }
|
||||
// StringBuilder sb = new StringBuilder();
|
||||
// offset += consumeUntil(skeleton, offset, ':', sb);
|
||||
// String padPositionString = sb.toString();
|
||||
// sb.setLength(0);
|
||||
// offset += consumeUntil(skeleton, offset, ' ', sb);
|
||||
// String string = (sb.length() == 0) ? " " : sb.toString();
|
||||
// PadPosition position = Enum.valueOf(PadPosition.class, padPositionString);
|
||||
// output.padder = PaddingImpl.getInstance(string, width, position);
|
||||
// }
|
||||
// return offset - originalOffset;
|
||||
// }
|
||||
|
||||
private static void integerWidthToSkeleton(IntegerWidth value, StringBuilder sb) {
|
||||
sb.append(value.minInt);
|
||||
if (value.maxInt != value.minInt) {
|
||||
sb.append('-');
|
||||
if (value.maxInt != -1) {
|
||||
sb.append(value.maxInt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int skeletonToIntegerWidth(String skeleton, int offset, MacroProps output) {
|
||||
int originalOffset = offset;
|
||||
long intResult = consumeInt(skeleton, offset);
|
||||
offset += intResult & 0xffffffff;
|
||||
int minInt = (int) (intResult >>> 32);
|
||||
char c1 = safeCharAt(skeleton, --offset);
|
||||
int maxInt;
|
||||
if (c1 == '-') {
|
||||
intResult = consumeInt(skeleton, offset);
|
||||
offset += intResult & 0xffffffff;
|
||||
maxInt = (int) (intResult >>> 32);
|
||||
}
|
||||
}
|
||||
|
||||
private static void symbolsToSkeleton(Object value, StringBuilder sb) {
|
||||
if (value instanceof DecimalFormatSymbols) {
|
||||
// TODO: Check to see if any of the symbols are not default?
|
||||
sb.append("loc:");
|
||||
sb.append(((DecimalFormatSymbols) value).getULocale());
|
||||
} else {
|
||||
sb.append("ns:");
|
||||
sb.append(((NumberingSystem) value).getName());
|
||||
}
|
||||
}
|
||||
|
||||
private static void unitWidthToSkeleton(UnitWidth value, StringBuilder sb) {
|
||||
sb.append(value.name());
|
||||
}
|
||||
|
||||
private static int skeletonToUnitWidth(String skeleton, int offset, MacroProps output) {
|
||||
int originalOffset = offset;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
offset += consumeUntil(skeleton, offset, ' ', sb);
|
||||
output.unitWidth = Enum.valueOf(UnitWidth.class, sb.toString());
|
||||
return offset - originalOffset;
|
||||
}
|
||||
|
||||
private static void signToSkeleton(SignDisplay value, StringBuilder sb) {
|
||||
sb.append(value.name());
|
||||
}
|
||||
|
||||
private static int skeletonToSign(String skeleton, int offset, MacroProps output) {
|
||||
int originalOffset = offset;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
offset += consumeUntil(skeleton, offset, ' ', sb);
|
||||
output.sign = Enum.valueOf(SignDisplay.class, sb.toString());
|
||||
return offset - originalOffset;
|
||||
}
|
||||
|
||||
private static void decimalToSkeleton(DecimalMarkDisplay value, StringBuilder sb) {
|
||||
sb.append(value.name());
|
||||
}
|
||||
|
||||
private static int skeletonToDecimal(String skeleton, int offset, MacroProps output) {
|
||||
int originalOffset = offset;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
offset += consumeUntil(skeleton, offset, ' ', sb);
|
||||
output.decimal = Enum.valueOf(DecimalMarkDisplay.class, sb.toString());
|
||||
return offset - originalOffset;
|
||||
}
|
||||
|
||||
private static char safeCharAt(String str, int offset) {
|
||||
if (offset < str.length()) {
|
||||
return str.charAt(offset);
|
||||
} else {
|
||||
return ' ';
|
||||
}
|
||||
}
|
||||
|
||||
private static int consumeUntil(String skeleton, int offset, char brk, StringBuilder sb) {
|
||||
int originalOffset = offset;
|
||||
char c = safeCharAt(skeleton, offset++);
|
||||
while (c != brk) {
|
||||
if (sb != null)
|
||||
sb.append(c);
|
||||
c = safeCharAt(skeleton, offset++);
|
||||
}
|
||||
return offset - originalOffset;
|
||||
}
|
||||
|
||||
private static long consumeInt(String skeleton, int offset) {
|
||||
int originalOffset = offset;
|
||||
char c = safeCharAt(skeleton, offset++);
|
||||
int result = 0;
|
||||
while ('0' <= c && c <= '9') {
|
||||
result = (result * 10) + (c - '0');
|
||||
c = safeCharAt(skeleton, offset++);
|
||||
}
|
||||
return (offset - originalOffset) | (((long) result) << 32);
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
// © 2017 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html#License
|
||||
package newapi.impl;
|
||||
|
||||
import java.math.RoundingMode;
|
||||
|
||||
import com.ibm.icu.text.DecimalFormatSymbols;
|
||||
import com.ibm.icu.text.NumberingSystem;
|
||||
import com.ibm.icu.util.Currency;
|
||||
import com.ibm.icu.util.Currency.CurrencyUsage;
|
||||
import com.ibm.icu.util.MeasureUnit;
|
||||
import com.ibm.icu.util.NoUnit;
|
||||
import com.ibm.icu.util.ULocale;
|
||||
|
||||
import newapi.Grouper;
|
||||
import newapi.Notation;
|
||||
import newapi.NumberFormatter;
|
||||
import newapi.NumberFormatter.DecimalMarkDisplay;
|
||||
import newapi.NumberFormatter.SignDisplay;
|
||||
import newapi.NumberFormatter.UnitWidth;
|
||||
import newapi.Rounder;
|
||||
import newapi.UnlocalizedNumberFormatter;
|
||||
|
||||
public class demo {
|
||||
public static void main(String[] args) {
|
||||
System.out.println(NumberingSystem.LATIN.getDescription());
|
||||
UnlocalizedNumberFormatter formatter =
|
||||
NumberFormatter.with()
|
||||
.notation(Notation.compactShort())
|
||||
.notation(Notation.scientific().withExponentSignDisplay(SignDisplay.ALWAYS))
|
||||
.notation(Notation.engineering().withMinExponentDigits(2))
|
||||
.notation(Notation.simple())
|
||||
.unit(Currency.getInstance("GBP"))
|
||||
.unit(NoUnit.PERCENT)
|
||||
.unit(MeasureUnit.CUBIC_METER)
|
||||
.unitWidth(UnitWidth.SHORT)
|
||||
// .rounding(Rounding.fixedSignificantDigits(3))
|
||||
// .rounding(
|
||||
// (BigDecimal input) -> {
|
||||
// return input.divide(new BigDecimal("0.02"), 0).multiply(new BigDecimal("0.02"));
|
||||
// })
|
||||
.rounding(Rounder.fixedFraction(2).withMode(RoundingMode.HALF_UP))
|
||||
.rounding(Rounder.integer().withMode(RoundingMode.CEILING))
|
||||
.rounding(Rounder.currency(CurrencyUsage.STANDARD))
|
||||
// .grouping(
|
||||
// (int position, BigDecimal number) -> {
|
||||
// return (position % 3) == 0;
|
||||
// })
|
||||
.grouping(Grouper.defaults())
|
||||
.grouping(Grouper.none())
|
||||
.grouping(Grouper.min2())
|
||||
// .padding(Padding.codePoints(' ', 8, PadPosition.AFTER_PREFIX))
|
||||
.sign(SignDisplay.ALWAYS)
|
||||
.decimal(DecimalMarkDisplay.ALWAYS)
|
||||
.symbols(DecimalFormatSymbols.getInstance(new ULocale("fr@digits=ascii")))
|
||||
.symbols(NumberingSystem.getInstanceByName("arab"))
|
||||
.symbols(NumberingSystem.LATIN);
|
||||
System.out.println(formatter.toSkeleton());
|
||||
System.out.println(formatter.locale(ULocale.ENGLISH).format(0.98381).toString());
|
||||
// .locale(Locale.ENGLISH)
|
||||
// .format(123.45)
|
||||
// .toString();
|
||||
}
|
||||
}
|
|
@ -195,25 +195,6 @@ pattern format output breaks
|
|||
#E0 52413 5,2413E4 K
|
||||
0E0 52413 5E4
|
||||
|
||||
test scientific with grouping
|
||||
set locale en
|
||||
set pattern #,##0.000E0
|
||||
begin
|
||||
format output breaks
|
||||
// J throws an IllegalArgumentException when parsing the pattern.
|
||||
// C sets error code to U_MALFORMED_EXPONENTIAL_PATTERN.
|
||||
1 1.000E0 CJ
|
||||
11 11.00E0 CJ
|
||||
111 111.0E0 CJ
|
||||
// K doesn't print the grouping separator ("1111E0")
|
||||
1111 1,111E0 CJK
|
||||
// K prints too many digits ("1.1111E4")
|
||||
11111 1.111E4 CJK
|
||||
111111 11.11E4 CJK
|
||||
1111111 111.1E4 CJK
|
||||
11111111 1,111E4 CJK
|
||||
111111111 1.111E8 CJK
|
||||
|
||||
test percents
|
||||
set locale fr
|
||||
begin
|
||||
|
|
|
@ -10,18 +10,17 @@ import org.junit.Test;
|
|||
|
||||
import com.ibm.icu.dev.test.TestUtil;
|
||||
import com.ibm.icu.impl.number.DecimalFormatProperties;
|
||||
import com.ibm.icu.impl.number.Padder.PadPosition;
|
||||
import com.ibm.icu.impl.number.Parse.ParseMode;
|
||||
import com.ibm.icu.impl.number.PatternStringParser;
|
||||
import com.ibm.icu.impl.number.PatternStringUtils;
|
||||
import com.ibm.icu.number.LocalizedNumberFormatter;
|
||||
import com.ibm.icu.number.NumberFormatter;
|
||||
import com.ibm.icu.text.DecimalFormatSymbols;
|
||||
import com.ibm.icu.text.DecimalFormat_ICU58;
|
||||
import com.ibm.icu.util.CurrencyAmount;
|
||||
import com.ibm.icu.util.ULocale;
|
||||
|
||||
import newapi.LocalizedNumberFormatter;
|
||||
import newapi.NumberFormatter;
|
||||
import newapi.impl.Padder.PadPosition;
|
||||
|
||||
public class NumberFormatDataDrivenTest {
|
||||
|
||||
private static ULocale EN = new ULocale("en");
|
||||
|
|
|
@ -2750,7 +2750,9 @@ public class NumberFormatTest extends TestFmwk {
|
|||
|
||||
@Test
|
||||
public void TestScientificWithGrouping() {
|
||||
DecimalFormat df = new DecimalFormat("#,##0.000E0");
|
||||
// Grouping separators are not allowed in the pattern, but we can enable them via the API.
|
||||
DecimalFormat df = new DecimalFormat("###0.000E0");
|
||||
df.setGroupingUsed(true);
|
||||
expect2(df, 123, "123.0E0");
|
||||
expect2(df, 1234, "1,234E0");
|
||||
expect2(df, 12340, "1.234E4");
|
||||
|
|
|
@ -20,13 +20,12 @@ import com.ibm.icu.impl.number.DecimalQuantity_64BitBCD;
|
|||
import com.ibm.icu.impl.number.DecimalQuantity_ByteArrayBCD;
|
||||
import com.ibm.icu.impl.number.DecimalQuantity_DualStorageBCD;
|
||||
import com.ibm.icu.impl.number.DecimalQuantity_SimpleStorage;
|
||||
import com.ibm.icu.number.LocalizedNumberFormatter;
|
||||
import com.ibm.icu.number.NumberFormatter;
|
||||
import com.ibm.icu.text.CompactDecimalFormat.CompactStyle;
|
||||
import com.ibm.icu.text.DecimalFormatSymbols;
|
||||
import com.ibm.icu.util.ULocale;
|
||||
|
||||
import newapi.LocalizedNumberFormatter;
|
||||
import newapi.NumberFormatter;
|
||||
|
||||
/** TODO: This is a temporary name for this class. Suggestions for a better name? */
|
||||
public class DecimalQuantityTest extends TestFmwk {
|
||||
|
||||
|
|
|
@ -8,12 +8,12 @@ import static org.junit.Assert.assertTrue;
|
|||
import org.junit.Test;
|
||||
|
||||
import com.ibm.icu.impl.SimpleFormatterImpl;
|
||||
import com.ibm.icu.impl.number.ConstantAffixModifier;
|
||||
import com.ibm.icu.impl.number.ConstantMultiFieldModifier;
|
||||
import com.ibm.icu.impl.number.CurrencySpacingEnabledModifier;
|
||||
import com.ibm.icu.impl.number.Modifier;
|
||||
import com.ibm.icu.impl.number.NumberStringBuilder;
|
||||
import com.ibm.icu.impl.number.modifiers.ConstantAffixModifier;
|
||||
import com.ibm.icu.impl.number.modifiers.ConstantMultiFieldModifier;
|
||||
import com.ibm.icu.impl.number.modifiers.CurrencySpacingEnabledModifier;
|
||||
import com.ibm.icu.impl.number.modifiers.SimpleModifier;
|
||||
import com.ibm.icu.impl.number.SimpleModifier;
|
||||
import com.ibm.icu.text.DecimalFormatSymbols;
|
||||
import com.ibm.icu.text.NumberFormat;
|
||||
import com.ibm.icu.util.ULocale;
|
||||
|
|
|
@ -10,17 +10,16 @@ import org.junit.Test;
|
|||
|
||||
import com.ibm.icu.impl.number.DecimalQuantity;
|
||||
import com.ibm.icu.impl.number.DecimalQuantity_DualStorageBCD;
|
||||
import com.ibm.icu.impl.number.MicroProps;
|
||||
import com.ibm.icu.impl.number.MutablePatternModifier;
|
||||
import com.ibm.icu.impl.number.NumberStringBuilder;
|
||||
import com.ibm.icu.impl.number.PatternStringParser;
|
||||
import com.ibm.icu.number.NumberFormatter.SignDisplay;
|
||||
import com.ibm.icu.number.NumberFormatter.UnitWidth;
|
||||
import com.ibm.icu.text.DecimalFormatSymbols;
|
||||
import com.ibm.icu.util.Currency;
|
||||
import com.ibm.icu.util.ULocale;
|
||||
|
||||
import newapi.NumberFormatter.SignDisplay;
|
||||
import newapi.NumberFormatter.UnitWidth;
|
||||
import newapi.impl.MicroProps;
|
||||
import newapi.impl.MutablePatternModifier;
|
||||
|
||||
public class MutablePatternModifierTest {
|
||||
|
||||
@Test
|
||||
|
|
|
@ -6,12 +6,26 @@ import static org.junit.Assert.assertEquals;
|
|||
import static org.junit.Assert.assertNotEquals;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.ibm.icu.impl.number.Padder;
|
||||
import com.ibm.icu.impl.number.Padder.PadPosition;
|
||||
import com.ibm.icu.impl.number.PatternStringParser;
|
||||
import com.ibm.icu.number.FormattedNumber;
|
||||
import com.ibm.icu.number.Grouper;
|
||||
import com.ibm.icu.number.IntegerWidth;
|
||||
import com.ibm.icu.number.LocalizedNumberFormatter;
|
||||
import com.ibm.icu.number.Notation;
|
||||
import com.ibm.icu.number.NumberFormatter;
|
||||
import com.ibm.icu.number.NumberFormatter.DecimalSeparatorDisplay;
|
||||
import com.ibm.icu.number.NumberFormatter.SignDisplay;
|
||||
import com.ibm.icu.number.NumberFormatter.UnitWidth;
|
||||
import com.ibm.icu.number.Rounder;
|
||||
import com.ibm.icu.number.UnlocalizedNumberFormatter;
|
||||
import com.ibm.icu.text.DecimalFormatSymbols;
|
||||
import com.ibm.icu.text.NumberingSystem;
|
||||
import com.ibm.icu.util.Currency;
|
||||
|
@ -22,25 +36,12 @@ import com.ibm.icu.util.MeasureUnit;
|
|||
import com.ibm.icu.util.NoUnit;
|
||||
import com.ibm.icu.util.ULocale;
|
||||
|
||||
import newapi.FormattedNumber;
|
||||
import newapi.Grouper;
|
||||
import newapi.IntegerWidth;
|
||||
import newapi.LocalizedNumberFormatter;
|
||||
import newapi.Notation;
|
||||
import newapi.NumberFormatter;
|
||||
import newapi.NumberFormatter.DecimalMarkDisplay;
|
||||
import newapi.NumberFormatter.SignDisplay;
|
||||
import newapi.NumberFormatter.UnitWidth;
|
||||
import newapi.Rounder;
|
||||
import newapi.UnlocalizedNumberFormatter;
|
||||
import newapi.impl.Padder;
|
||||
import newapi.impl.Padder.PadPosition;
|
||||
|
||||
public class NumberFormatterTest {
|
||||
|
||||
private static final Currency USD = Currency.getInstance("USD");
|
||||
private static final Currency GBP = Currency.getInstance("GBP");
|
||||
private static final Currency CZK = Currency.getInstance("CZK");
|
||||
private static final Currency CAD = Currency.getInstance("CAD");
|
||||
|
||||
@Test
|
||||
public void notationSimple() {
|
||||
|
@ -59,6 +60,21 @@ public class NumberFormatterTest {
|
|||
"0.008765",
|
||||
"0");
|
||||
|
||||
assertFormatDescendingBig(
|
||||
"Big Simple",
|
||||
"",
|
||||
NumberFormatter.with().notation(Notation.simple()),
|
||||
ULocale.ENGLISH,
|
||||
"87,650,000",
|
||||
"8,765,000",
|
||||
"876,500",
|
||||
"87,650",
|
||||
"8,765",
|
||||
"876.5",
|
||||
"87.65",
|
||||
"8.765",
|
||||
"0");
|
||||
|
||||
assertFormatSingle(
|
||||
"Basic with Negative Sign",
|
||||
"",
|
||||
|
@ -141,34 +157,34 @@ public class NumberFormatterTest {
|
|||
|
||||
@Test
|
||||
public void notationCompact() {
|
||||
assertFormatDescending(
|
||||
assertFormatDescendingBig(
|
||||
"Compact Short",
|
||||
"C",
|
||||
NumberFormatter.with().notation(Notation.compactShort()),
|
||||
ULocale.ENGLISH,
|
||||
"88M",
|
||||
"8.8M",
|
||||
"876K",
|
||||
"88K",
|
||||
"8.8K",
|
||||
"876",
|
||||
"88",
|
||||
"8.8",
|
||||
"0.88",
|
||||
"0.088",
|
||||
"0.0088",
|
||||
"0");
|
||||
|
||||
assertFormatDescending(
|
||||
assertFormatDescendingBig(
|
||||
"Compact Long",
|
||||
"CC",
|
||||
NumberFormatter.with().notation(Notation.compactLong()),
|
||||
ULocale.ENGLISH,
|
||||
"88 million",
|
||||
"8.8 million",
|
||||
"876 thousand",
|
||||
"88 thousand",
|
||||
"8.8 thousand",
|
||||
"876",
|
||||
"88",
|
||||
"8.8",
|
||||
"0.88",
|
||||
"0.088",
|
||||
"0.0088",
|
||||
"0");
|
||||
|
||||
assertFormatDescending(
|
||||
|
@ -189,10 +205,7 @@ public class NumberFormatterTest {
|
|||
assertFormatDescending(
|
||||
"Compact Short with ISO Currency",
|
||||
"C $USD unit-width=ISO_CODE",
|
||||
NumberFormatter.with()
|
||||
.notation(Notation.compactShort())
|
||||
.unit(USD)
|
||||
.unitWidth(UnitWidth.ISO_CODE),
|
||||
NumberFormatter.with().notation(Notation.compactShort()).unit(USD).unitWidth(UnitWidth.ISO_CODE),
|
||||
ULocale.ENGLISH,
|
||||
"USD 88K",
|
||||
"USD 8.8K",
|
||||
|
@ -207,10 +220,7 @@ public class NumberFormatterTest {
|
|||
assertFormatDescending(
|
||||
"Compact Short with Long Name Currency",
|
||||
"C $USD unit-width=FULL_NAME",
|
||||
NumberFormatter.with()
|
||||
.notation(Notation.compactShort())
|
||||
.unit(USD)
|
||||
.unitWidth(UnitWidth.FULL_NAME),
|
||||
NumberFormatter.with().notation(Notation.compactShort()).unit(USD).unitWidth(UnitWidth.FULL_NAME),
|
||||
ULocale.ENGLISH,
|
||||
"88K US dollars",
|
||||
"8.8K US dollars",
|
||||
|
@ -244,10 +254,7 @@ public class NumberFormatterTest {
|
|||
assertFormatDescending(
|
||||
"Compact Long with ISO Currency",
|
||||
"CC $USD unit-width=ISO_CODE",
|
||||
NumberFormatter.with()
|
||||
.notation(Notation.compactLong())
|
||||
.unit(USD)
|
||||
.unitWidth(UnitWidth.ISO_CODE),
|
||||
NumberFormatter.with().notation(Notation.compactLong()).unit(USD).unitWidth(UnitWidth.ISO_CODE),
|
||||
ULocale.ENGLISH,
|
||||
"USD 88K", // should be something like "USD 88 thousand"
|
||||
"USD 8.8K",
|
||||
|
@ -263,10 +270,7 @@ public class NumberFormatterTest {
|
|||
assertFormatDescending(
|
||||
"Compact Long with Long Name Currency",
|
||||
"CC $USD unit-width=FULL_NAME",
|
||||
NumberFormatter.with()
|
||||
.notation(Notation.compactLong())
|
||||
.unit(USD)
|
||||
.unitWidth(UnitWidth.FULL_NAME),
|
||||
NumberFormatter.with().notation(Notation.compactLong()).unit(USD).unitWidth(UnitWidth.FULL_NAME),
|
||||
ULocale.ENGLISH,
|
||||
"88 thousand US dollars",
|
||||
"8.8 thousand US dollars",
|
||||
|
@ -442,6 +446,24 @@ public class NumberFormatterTest {
|
|||
ULocale.forLanguageTag("en-GB"),
|
||||
5.43,
|
||||
"5.43 m²");
|
||||
|
||||
// es_US has "{0}°" for unitsNarrow/temperature/FAHRENHEIT.
|
||||
// NOTE: This example is in the documentation.
|
||||
assertFormatSingle(
|
||||
"MeasureUnit Difference between Narrow and Short (Narrow Version)",
|
||||
"",
|
||||
NumberFormatter.with().unit(MeasureUnit.FAHRENHEIT).unitWidth(UnitWidth.NARROW),
|
||||
ULocale.forLanguageTag("es-US"),
|
||||
5.43,
|
||||
"5.43°");
|
||||
|
||||
assertFormatSingle(
|
||||
"MeasureUnit Difference between Narrow and Short (Short Version)",
|
||||
"",
|
||||
NumberFormatter.with().unit(MeasureUnit.FAHRENHEIT).unitWidth(UnitWidth.SHORT),
|
||||
ULocale.forLanguageTag("es-US"),
|
||||
5.43,
|
||||
"5.43 °F");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -491,6 +513,21 @@ public class NumberFormatterTest {
|
|||
"0.01 British pounds",
|
||||
"0.00 British pounds");
|
||||
|
||||
assertFormatDescending(
|
||||
"Currency Hidden",
|
||||
"$GBP unit-width=HIDDEN",
|
||||
NumberFormatter.with().unit(GBP).unitWidth(UnitWidth.HIDDEN),
|
||||
ULocale.ENGLISH,
|
||||
"87,650.00",
|
||||
"8,765.00",
|
||||
"876.50",
|
||||
"87.65",
|
||||
"8.76",
|
||||
"0.88",
|
||||
"0.09",
|
||||
"0.01",
|
||||
"0.00");
|
||||
|
||||
assertFormatSingleMeasure(
|
||||
"Currency with CurrencyAmount Input",
|
||||
"",
|
||||
|
@ -517,6 +554,25 @@ public class NumberFormatterTest {
|
|||
ULocale.ENGLISH,
|
||||
-9876543.21,
|
||||
"-£9,876,543.21");
|
||||
|
||||
// The full currency symbol is not shown in NARROW format.
|
||||
// NOTE: This example is in the documentation.
|
||||
// FIXME: Narrow Currency does not currently work; see #11666
|
||||
assertFormatSingle(
|
||||
"Currency Difference between Narrow and Short (Narrow Version)",
|
||||
"",
|
||||
NumberFormatter.with().unit(USD).unitWidth(UnitWidth.NARROW),
|
||||
ULocale.forLanguageTag("en-CA"),
|
||||
5.43,
|
||||
"US$5.43");
|
||||
|
||||
assertFormatSingle(
|
||||
"Currency Difference between Narrow and Short (Short Version)",
|
||||
"",
|
||||
NumberFormatter.with().unit(USD).unitWidth(UnitWidth.SHORT),
|
||||
ULocale.forLanguageTag("en_CA"),
|
||||
5.43,
|
||||
"US$ 5.43");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -526,14 +582,14 @@ public class NumberFormatterTest {
|
|||
"%",
|
||||
NumberFormatter.with().unit(NoUnit.PERCENT),
|
||||
ULocale.ENGLISH,
|
||||
"8,765,000%",
|
||||
"876,500%",
|
||||
"87,650%",
|
||||
"8,765%",
|
||||
"876.5%",
|
||||
"87.65%",
|
||||
"8.765%",
|
||||
"0.8765%",
|
||||
"0.08765%",
|
||||
"0.008765%",
|
||||
"0%");
|
||||
|
||||
assertFormatDescending(
|
||||
|
@ -541,14 +597,14 @@ public class NumberFormatterTest {
|
|||
"%%",
|
||||
NumberFormatter.with().unit(NoUnit.PERMILLE),
|
||||
ULocale.ENGLISH,
|
||||
"87,650,000‰",
|
||||
"8,765,000‰",
|
||||
"876,500‰",
|
||||
"87,650‰",
|
||||
"8,765‰",
|
||||
"876.5‰",
|
||||
"87.65‰",
|
||||
"8.765‰",
|
||||
"0.8765‰",
|
||||
"0.08765‰",
|
||||
"0.008765‰",
|
||||
"0‰");
|
||||
|
||||
assertFormatSingle(
|
||||
|
@ -564,8 +620,8 @@ public class NumberFormatterTest {
|
|||
"%",
|
||||
NumberFormatter.with().unit(NoUnit.PERCENT),
|
||||
ULocale.ENGLISH,
|
||||
-0.987654321,
|
||||
"-98.7654321%");
|
||||
-98.7654321,
|
||||
"-98.765432%");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -792,6 +848,21 @@ public class NumberFormatterTest {
|
|||
"0.0",
|
||||
"0.0");
|
||||
|
||||
assertFormatDescending(
|
||||
"Increment with Min Fraction",
|
||||
"M0.5",
|
||||
NumberFormatter.with().rounding(Rounder.increment(new BigDecimal("0.50"))),
|
||||
ULocale.ENGLISH,
|
||||
"87,650.00",
|
||||
"8,765.00",
|
||||
"876.50",
|
||||
"87.50",
|
||||
"9.00",
|
||||
"1.00",
|
||||
"0.00",
|
||||
"0.00",
|
||||
"0.00");
|
||||
|
||||
assertFormatDescending(
|
||||
"Currency Standard",
|
||||
"$CZK GSTANDARD",
|
||||
|
@ -822,6 +893,21 @@ public class NumberFormatterTest {
|
|||
"CZK 0",
|
||||
"CZK 0");
|
||||
|
||||
assertFormatDescending(
|
||||
"Currency Cash with Nickel Rounding",
|
||||
"$CAD GCASH",
|
||||
NumberFormatter.with().rounding(Rounder.currency(CurrencyUsage.CASH)).unit(CAD),
|
||||
ULocale.ENGLISH,
|
||||
"CA$87,650.00",
|
||||
"CA$8,765.00",
|
||||
"CA$876.50",
|
||||
"CA$87.65",
|
||||
"CA$8.75",
|
||||
"CA$0.90",
|
||||
"CA$0.10",
|
||||
"CA$0.00",
|
||||
"CA$0.00");
|
||||
|
||||
assertFormatDescending(
|
||||
"Currency not in top-level fluent chain",
|
||||
"F0",
|
||||
|
@ -836,71 +922,100 @@ public class NumberFormatterTest {
|
|||
"0",
|
||||
"0",
|
||||
"0");
|
||||
|
||||
// NOTE: Other tests cover the behavior of the other rounding modes.
|
||||
assertFormatDescending(
|
||||
"Rounding Mode CEILING",
|
||||
"",
|
||||
NumberFormatter.with().rounding(Rounder.integer().withMode(RoundingMode.CEILING)),
|
||||
ULocale.ENGLISH,
|
||||
"87,650",
|
||||
"8,765",
|
||||
"877",
|
||||
"88",
|
||||
"9",
|
||||
"1",
|
||||
"1",
|
||||
"1",
|
||||
"0");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void grouping() {
|
||||
// NoUnit.PERMILLE multiplies all the number by 10^3 (good for testing grouping).
|
||||
// Note that en-US is already performed in the unitPercent() function.
|
||||
assertFormatDescending(
|
||||
"Indic Grouping",
|
||||
"%% grouping=defaults",
|
||||
NumberFormatter.with().unit(NoUnit.PERMILLE).grouping(Grouper.defaults()),
|
||||
new ULocale("en-IN"),
|
||||
"8,76,50,000‰",
|
||||
"87,65,000‰",
|
||||
"8,76,500‰",
|
||||
"87,650‰",
|
||||
"8,765‰",
|
||||
"876.5‰",
|
||||
"87.65‰",
|
||||
"8.765‰",
|
||||
"0‰");
|
||||
|
||||
assertFormatDescending(
|
||||
"Western Grouping, Min 2",
|
||||
"%% grouping=min2",
|
||||
NumberFormatter.with().unit(NoUnit.PERMILLE).grouping(Grouper.min2()),
|
||||
assertFormatDescendingBig(
|
||||
"Western Grouping",
|
||||
"grouping=defaults",
|
||||
NumberFormatter.with().grouping(Grouper.defaults()),
|
||||
ULocale.ENGLISH,
|
||||
"87,650,000‰",
|
||||
"8,765,000‰",
|
||||
"876,500‰",
|
||||
"87,650‰",
|
||||
"8765‰",
|
||||
"876.5‰",
|
||||
"87.65‰",
|
||||
"8.765‰",
|
||||
"0‰");
|
||||
"87,650,000",
|
||||
"8,765,000",
|
||||
"876,500",
|
||||
"87,650",
|
||||
"8,765",
|
||||
"876.5",
|
||||
"87.65",
|
||||
"8.765",
|
||||
"0");
|
||||
|
||||
assertFormatDescending(
|
||||
assertFormatDescendingBig(
|
||||
"Indic Grouping",
|
||||
"grouping=defaults",
|
||||
NumberFormatter.with().grouping(Grouper.defaults()),
|
||||
new ULocale("en-IN"),
|
||||
"8,76,50,000",
|
||||
"87,65,000",
|
||||
"8,76,500",
|
||||
"87,650",
|
||||
"8,765",
|
||||
"876.5",
|
||||
"87.65",
|
||||
"8.765",
|
||||
"0");
|
||||
|
||||
assertFormatDescendingBig(
|
||||
"Western Grouping, Min 2",
|
||||
"grouping=min2",
|
||||
NumberFormatter.with().grouping(Grouper.minTwoDigits()),
|
||||
ULocale.ENGLISH,
|
||||
"87,650,000",
|
||||
"8,765,000",
|
||||
"876,500",
|
||||
"87,650",
|
||||
"8765",
|
||||
"876.5",
|
||||
"87.65",
|
||||
"8.765",
|
||||
"0");
|
||||
|
||||
assertFormatDescendingBig(
|
||||
"Indic Grouping, Min 2",
|
||||
"%% grouping=min2",
|
||||
NumberFormatter.with().unit(NoUnit.PERMILLE).grouping(Grouper.min2()),
|
||||
"grouping=min2",
|
||||
NumberFormatter.with().grouping(Grouper.minTwoDigits()),
|
||||
new ULocale("en-IN"),
|
||||
"8,76,50,000‰",
|
||||
"87,65,000‰",
|
||||
"8,76,500‰",
|
||||
"87,650‰",
|
||||
"8765‰",
|
||||
"876.5‰",
|
||||
"87.65‰",
|
||||
"8.765‰",
|
||||
"0‰");
|
||||
"8,76,50,000",
|
||||
"87,65,000",
|
||||
"8,76,500",
|
||||
"87,650",
|
||||
"8765",
|
||||
"876.5",
|
||||
"87.65",
|
||||
"8.765",
|
||||
"0");
|
||||
|
||||
assertFormatDescending(
|
||||
assertFormatDescendingBig(
|
||||
"No Grouping",
|
||||
"%% grouping=none",
|
||||
NumberFormatter.with().unit(NoUnit.PERMILLE).grouping(Grouper.none()),
|
||||
"grouping=none",
|
||||
NumberFormatter.with().grouping(Grouper.none()),
|
||||
new ULocale("en-IN"),
|
||||
"87650000‰",
|
||||
"8765000‰",
|
||||
"876500‰",
|
||||
"87650‰",
|
||||
"8765‰",
|
||||
"876.5‰",
|
||||
"87.65‰",
|
||||
"8.765‰",
|
||||
"0‰");
|
||||
"87650000",
|
||||
"8765000",
|
||||
"876500",
|
||||
"87650",
|
||||
"8765",
|
||||
"876.5",
|
||||
"87.65",
|
||||
"8.765",
|
||||
"0");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1004,7 +1119,7 @@ public class NumberFormatterTest {
|
|||
NumberFormatter.with().padding(Padder.codePoints('*', 8, PadPosition.BEFORE_SUFFIX))
|
||||
.unit(NoUnit.PERCENT),
|
||||
ULocale.ENGLISH,
|
||||
0.8888,
|
||||
88.88,
|
||||
"88.88**%");
|
||||
|
||||
assertFormatSingle(
|
||||
|
@ -1013,14 +1128,14 @@ public class NumberFormatterTest {
|
|||
NumberFormatter.with().padding(Padder.codePoints('*', 8, PadPosition.AFTER_SUFFIX))
|
||||
.unit(NoUnit.PERCENT),
|
||||
ULocale.ENGLISH,
|
||||
0.8888,
|
||||
88.88,
|
||||
"88.88%**");
|
||||
|
||||
assertFormatSingle(
|
||||
"Currency Spacing with Zero Digit Padding Broken",
|
||||
"$GBP unit-width=ISO_CODE",
|
||||
NumberFormatter.with().padding(Padder.codePoints('0', 12, PadPosition.AFTER_PREFIX)).unit(GBP)
|
||||
.unitWidth(UnitWidth.ISO_CODE),
|
||||
.unitWidth(UnitWidth.ISO_CODE),
|
||||
ULocale.ENGLISH,
|
||||
514.23,
|
||||
"GBP 000514.23"); // TODO: This is broken; it renders too wide (13 instead of 12).
|
||||
|
@ -1135,15 +1250,15 @@ public class NumberFormatterTest {
|
|||
"$USD symbols=ns:latn",
|
||||
NumberFormatter.with().symbols(NumberingSystem.LATIN).unit(USD),
|
||||
new ULocale("ar"),
|
||||
"87,650.00 US$",
|
||||
"8,765.00 US$",
|
||||
"876.50 US$",
|
||||
"87.65 US$",
|
||||
"8.76 US$",
|
||||
"0.88 US$",
|
||||
"0.09 US$",
|
||||
"0.01 US$",
|
||||
"0.00 US$");
|
||||
"US$ 87,650.00",
|
||||
"US$ 8,765.00",
|
||||
"US$ 876.50",
|
||||
"US$ 87.65",
|
||||
"US$ 8.76",
|
||||
"US$ 0.88",
|
||||
"US$ 0.09",
|
||||
"US$ 0.01",
|
||||
"US$ 0.00");
|
||||
|
||||
assertFormatDescending(
|
||||
"Math Numbering System with French Data",
|
||||
|
@ -1176,6 +1291,40 @@ public class NumberFormatterTest {
|
|||
12345.67,
|
||||
"\u1041\u1042,\u1043\u1044\u1045.\u1046\u1047");
|
||||
|
||||
// NOTE: Locale ar puts ¤ after the number in NS arab but before the number in NS latn.
|
||||
|
||||
assertFormatSingle(
|
||||
"Currency symbol should precede number in ar with NS latn",
|
||||
"",
|
||||
NumberFormatter.with().symbols(NumberingSystem.LATIN).unit(USD),
|
||||
new ULocale("ar"),
|
||||
12345.67,
|
||||
"US$ 12,345.67");
|
||||
|
||||
assertFormatSingle(
|
||||
"Currency symbol should precede number in ar@numbers=latn",
|
||||
"",
|
||||
NumberFormatter.with().unit(USD),
|
||||
new ULocale("ar@numbers=latn"),
|
||||
12345.67,
|
||||
"US$ 12,345.67");
|
||||
|
||||
assertFormatSingle(
|
||||
"Currency symbol should follow number in ar with NS arab",
|
||||
"",
|
||||
NumberFormatter.with().unit(USD),
|
||||
new ULocale("ar"),
|
||||
12345.67,
|
||||
"١٢٬٣٤٥٫٦٧ US$");
|
||||
|
||||
assertFormatSingle(
|
||||
"Currency symbol should follow number in ar@numbers=arab",
|
||||
"",
|
||||
NumberFormatter.with().unit(USD),
|
||||
new ULocale("ar@numbers=arab"),
|
||||
12345.67,
|
||||
"١٢٬٣٤٥٫٦٧ US$");
|
||||
|
||||
DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(new ULocale("de-CH"));
|
||||
UnlocalizedNumberFormatter f = NumberFormatter.with().symbols(symbols);
|
||||
symbols.setGroupingSeparatorString("!");
|
||||
|
@ -1300,6 +1449,14 @@ public class NumberFormatterTest {
|
|||
ULocale.ENGLISH,
|
||||
-444444,
|
||||
"($444,444.00)");
|
||||
|
||||
assertFormatSingle(
|
||||
"Sign Accounting Negative Hidden",
|
||||
"$USD unit-width=HIDDEN sign=ACCOUNTING",
|
||||
NumberFormatter.with().sign(SignDisplay.ACCOUNTING).unit(USD).unitWidth(UnitWidth.HIDDEN),
|
||||
ULocale.ENGLISH,
|
||||
-444444,
|
||||
"(444,444.00)");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1307,7 +1464,7 @@ public class NumberFormatterTest {
|
|||
assertFormatDescending(
|
||||
"Decimal Default",
|
||||
"decimal=AUTO",
|
||||
NumberFormatter.with().decimal(DecimalMarkDisplay.AUTO),
|
||||
NumberFormatter.with().decimal(DecimalSeparatorDisplay.AUTO),
|
||||
ULocale.ENGLISH,
|
||||
"87,650",
|
||||
"8,765",
|
||||
|
@ -1322,7 +1479,7 @@ public class NumberFormatterTest {
|
|||
assertFormatDescending(
|
||||
"Decimal Always Shown",
|
||||
"decimal=ALWAYS",
|
||||
NumberFormatter.with().decimal(DecimalMarkDisplay.ALWAYS),
|
||||
NumberFormatter.with().decimal(DecimalSeparatorDisplay.ALWAYS),
|
||||
ULocale.ENGLISH,
|
||||
"87,650.",
|
||||
"8,765.",
|
||||
|
@ -1394,17 +1551,38 @@ public class NumberFormatterTest {
|
|||
UnlocalizedNumberFormatter f,
|
||||
ULocale locale,
|
||||
String... expected) {
|
||||
assert expected.length == 9;
|
||||
assertEquals(message + ": Skeleton:", skeleton, f.toSkeleton());
|
||||
final double[] inputs = new double[] { 87650, 8765, 876.5, 87.65, 8.765, 0.8765, 0.08765, 0.008765, 0 };
|
||||
assertFormatDescending(message, skeleton, f, locale, inputs, expected);
|
||||
}
|
||||
|
||||
private static void assertFormatDescendingBig(
|
||||
String message,
|
||||
String skeleton,
|
||||
UnlocalizedNumberFormatter f,
|
||||
ULocale locale,
|
||||
String... expected) {
|
||||
final double[] inputs = new double[] { 87650000, 8765000, 876500, 87650, 8765, 876.5, 87.65, 8.765, 0 };
|
||||
assertFormatDescending(message, skeleton, f, locale, inputs, expected);
|
||||
}
|
||||
|
||||
private static void assertFormatDescending(
|
||||
String message,
|
||||
String skeleton,
|
||||
UnlocalizedNumberFormatter f,
|
||||
ULocale locale,
|
||||
double[] inputs,
|
||||
String... expected) {
|
||||
assert expected.length == 9;
|
||||
// TODO: Add a check for skeleton.
|
||||
// assertEquals(message + ": Skeleton:", skeleton, f.toSkeleton());
|
||||
LocalizedNumberFormatter l1 = f.threshold(0L).locale(locale); // no self-regulation
|
||||
LocalizedNumberFormatter l2 = f.threshold(1L).locale(locale); // all self-regulation
|
||||
for (int i = 0; i < 9; i++) {
|
||||
double d = inputs[i];
|
||||
String actual1 = l1.format(d).toString();
|
||||
assertEquals(message + ": L1: " + d, expected[i], actual1);
|
||||
assertEquals(message + ": Unsafe Path: " + d, expected[i], actual1);
|
||||
String actual2 = l2.format(d).toString();
|
||||
assertEquals(message + ": L2: " + d, expected[i], actual2);
|
||||
assertEquals(message + ": Safe Path: " + d, expected[i], actual2);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1415,7 +1593,8 @@ public class NumberFormatterTest {
|
|||
ULocale locale,
|
||||
Number input,
|
||||
String expected) {
|
||||
assertEquals(message + ": Skeleton:", skeleton, f.toSkeleton());
|
||||
// TODO: Add a check for skeleton.
|
||||
// assertEquals(message + ": Skeleton:", skeleton, f.toSkeleton());
|
||||
LocalizedNumberFormatter l1 = f.threshold(0L).locale(locale); // no self-regulation
|
||||
LocalizedNumberFormatter l2 = f.threshold(1L).locale(locale); // all self-regulation
|
||||
String actual1 = l1.format(input).toString();
|
||||
|
@ -1431,7 +1610,8 @@ public class NumberFormatterTest {
|
|||
ULocale locale,
|
||||
Measure input,
|
||||
String expected) {
|
||||
assertEquals(message + ": Skeleton:", skeleton, f.toSkeleton());
|
||||
// TODO: Add a check for skeleton.
|
||||
// assertEquals(message + ": Skeleton:", skeleton, f.toSkeleton());
|
||||
LocalizedNumberFormatter l1 = f.threshold(0L).locale(locale); // no self-regulation
|
||||
LocalizedNumberFormatter l2 = f.threshold(1L).locale(locale); // all self-regulation
|
||||
String actual1 = l1.format(input).toString();
|
||||
|
|
|
@ -33,6 +33,7 @@ import com.ibm.icu.impl.number.DecimalFormatProperties;
|
|||
import com.ibm.icu.impl.number.Parse.GroupingMode;
|
||||
import com.ibm.icu.impl.number.Parse.ParseMode;
|
||||
import com.ibm.icu.impl.number.PatternStringParser;
|
||||
import com.ibm.icu.impl.number.Padder.PadPosition;
|
||||
import com.ibm.icu.text.CompactDecimalFormat.CompactStyle;
|
||||
import com.ibm.icu.text.CurrencyPluralInfo;
|
||||
import com.ibm.icu.text.MeasureFormat.FormatWidth;
|
||||
|
@ -42,8 +43,6 @@ import com.ibm.icu.util.Currency.CurrencyUsage;
|
|||
import com.ibm.icu.util.MeasureUnit;
|
||||
import com.ibm.icu.util.ULocale;
|
||||
|
||||
import newapi.impl.Padder.PadPosition;
|
||||
|
||||
public class PropertiesTest {
|
||||
|
||||
@Test
|
||||
|
|
|
@ -45,6 +45,11 @@ public final class DecimalQuantity_64BitBCD extends DecimalQuantity_AbstractBCD
|
|||
copyFrom(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DecimalQuantity createCopy() {
|
||||
return new DecimalQuantity_64BitBCD(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte getDigitPos(int position) {
|
||||
if (position < 0 || position >= 16) return 0;
|
|
@ -45,6 +45,11 @@ public final class DecimalQuantity_ByteArrayBCD extends DecimalQuantity_Abstract
|
|||
copyFrom(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DecimalQuantity createCopy() {
|
||||
return new DecimalQuantity_ByteArrayBCD(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte getDigitPos(int position) {
|
||||
if (position < 0 || position > precision) return 0;
|
Loading…
Add table
Reference in a new issue