// License & terms of use: http://www.unicode.org/copyright.html#License
package com.ibm.icu.impl.number;
-import com.ibm.icu.text.DecimalFormatSymbols;
import com.ibm.icu.text.NumberFormat;
/**
return sb.toString();
}
- /**
- * Executes the unescape state machine. Replaces the unquoted characters "-", "+", "%", and "‰"
- * with their localized equivalents. Replaces "¤", "¤¤", and "¤¤¤" with the three argument
- * strings.
- *
- * <p>Example input: "'-'¤x"; example output: "-$x"
- *
- * @param affixPattern The original string to be unescaped.
- * @param symbols An instance of {@link DecimalFormatSymbols} for the locale of interest.
- * @param currency1 The string to replace "¤".
- * @param currency2 The string to replace "¤¤".
- * @param currency3 The string to replace "¤¤¤".
- * @param minusSign The string to replace "-". If null, symbols.getMinusSignString() is used.
- * @param output The {@link NumberStringBuilder} to which the result will be appended.
- */
- public static void unescape(
- CharSequence affixPattern,
- DecimalFormatSymbols symbols,
- String currency1,
- String currency2,
- String currency3,
- String minusSign,
- NumberStringBuilder output) {
- if (affixPattern == null || affixPattern.length() == 0) return;
- if (minusSign == null) minusSign = symbols.getMinusSignString();
- long tag = 0L;
- while (hasNext(tag, affixPattern)) {
- tag = nextToken(tag, affixPattern);
- int typeOrCp = getTypeOrCp(tag);
- NumberFormat.Field field = (typeOrCp < 0) ? getFieldForType(typeOrCp) : null;
- switch (typeOrCp) {
- case TYPE_MINUS_SIGN:
- output.append(minusSign, field);
- break;
- case TYPE_PLUS_SIGN:
- output.append(symbols.getPlusSignString(), field);
- break;
- case TYPE_PERCENT:
- output.append(symbols.getPercentString(), field);
- break;
- case TYPE_PERMILLE:
- output.append(symbols.getPerMillString(), field);
- break;
- case TYPE_CURRENCY_SINGLE:
- output.append(currency1, field);
- break;
- case TYPE_CURRENCY_DOUBLE:
- output.append(currency2, field);
- break;
- case TYPE_CURRENCY_TRIPLE:
- output.append(currency3, field);
- break;
- case TYPE_CURRENCY_QUAD:
- output.appendCodePoint('\uFFFD', field);
- break;
- case TYPE_CURRENCY_QUINT:
- // TODO: Add support for narrow currency symbols here.
- output.appendCodePoint('\uFFFD', field);
- break;
- case TYPE_CURRENCY_OVERFLOW:
- output.appendCodePoint('\uFFFD', field);
- break;
- default:
- output.appendCodePoint(typeOrCp, null);
- break;
- }
- }
- }
-
public static final NumberFormat.Field getFieldForType(int type) {
switch (type) {
case TYPE_MINUS_SIGN:
public CharSequence getSymbol(int type);
}
+ /**
+ * Executes the unescape state machine. Replaces the unquoted characters "-", "+", "%", "‰", and
+ * "¤" with the corresponding symbols provided by the {@link SymbolProvider}, and inserts the
+ * result into the NumberStringBuilder at the requested location.
+ *
+ * <p>Example input: "'-'¤x"; example output: "-$x"
+ *
+ * @param affixPattern The original string to be unescaped.
+ * @param output The NumberStringBuilder to mutate with the result.
+ * @param position The index into the NumberStringBuilder to insert the the string.
+ * @param provider An object to generate locale symbols.
+ */
public static int unescape(
CharSequence affixPattern,
NumberStringBuilder output,
+++ /dev/null
-// © 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 java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
-
-import com.ibm.icu.impl.number.Format.BeforeTargetAfterFormat;
-import com.ibm.icu.impl.number.Format.SingularFormat;
-import com.ibm.icu.impl.number.Format.TargetFormat;
-import com.ibm.icu.impl.number.formatters.BigDecimalMultiplier;
-import com.ibm.icu.impl.number.formatters.CompactDecimalFormat;
-import com.ibm.icu.impl.number.formatters.CurrencyFormat;
-import com.ibm.icu.impl.number.formatters.MagnitudeMultiplier;
-import com.ibm.icu.impl.number.formatters.MeasureFormat;
-import com.ibm.icu.impl.number.formatters.PaddingFormat;
-import com.ibm.icu.impl.number.formatters.PositiveDecimalFormat;
-import com.ibm.icu.impl.number.formatters.PositiveNegativeAffixFormat;
-import com.ibm.icu.impl.number.formatters.RoundingFormat;
-import com.ibm.icu.impl.number.formatters.ScientificFormat;
-import com.ibm.icu.text.DecimalFormatSymbols;
-import com.ibm.icu.text.PluralRules;
-import com.ibm.icu.util.ULocale;
-
-public class Endpoint {
- // public static Format from(DecimalFormatSymbols symbols, Properties properties)
- // throws ParseException {
- // Format format = new PositiveIntegerFormat(symbols, properties);
- // // TODO: integer-only format
- // format = new PositiveDecimalFormat((SelfContainedFormat) format, symbols, properties);
- // if (properties.useCompactDecimalFormat()) {
- // format = CompactDecimalFormat.getInstance((SingularFormat) format, symbols, properties);
- // } else {
- // format =
- // PositiveNegativeAffixFormat.getInstance((SingularFormat) format, symbols, properties);
- // }
- // if (properties.useRoundingInterval()) {
- // format = new IntervalRoundingFormat((SingularFormat) format, properties);
- // } else if (properties.useSignificantDigits()) {
- // format = new SignificantDigitsFormat((SingularFormat) format, properties);
- // } else if (properties.useFractionFormat()) {
- // format = new RoundingFormat((SingularFormat) format, properties);
- // }
- // return format;
- // }
-
- public static interface IProperties {
- static PluralRules DEFAULT_PLURAL_RULES = null;
-
- public PluralRules getPluralRules();
-
- public IProperties setPluralRules(PluralRules pluralRules);
- }
-
- public static Format fromBTA(Properties properties) {
- return fromBTA(properties, getSymbols());
- }
-
- public static SingularFormat fromBTA(Properties properties, Locale locale) {
- return fromBTA(properties, getSymbols(locale));
- }
-
- public static SingularFormat fromBTA(Properties properties, ULocale uLocale) {
- return fromBTA(properties, getSymbols(uLocale));
- }
-
- public static SingularFormat fromBTA(String pattern) {
- return fromBTA(getProperties(pattern), getSymbols());
- }
-
- public static SingularFormat fromBTA(String pattern, Locale locale) {
- return fromBTA(getProperties(pattern), getSymbols(locale));
- }
-
- public static SingularFormat fromBTA(String pattern, ULocale uLocale) {
- return fromBTA(getProperties(pattern), getSymbols(uLocale));
- }
-
- public static SingularFormat fromBTA(String pattern, DecimalFormatSymbols symbols) {
- return fromBTA(getProperties(pattern), symbols);
- }
-
- public static SingularFormat fromBTA(Properties properties, DecimalFormatSymbols symbols) {
-
- if (symbols == null) throw new IllegalArgumentException("symbols must not be null");
-
- // TODO: This fast track results in an improvement of about 10ns during formatting. See if
- // there is a way to implement it more elegantly.
- boolean canUseFastTrack = true;
- PluralRules rules = getPluralRules(symbols.getULocale(), properties);
- BeforeTargetAfterFormat format = new Format.BeforeTargetAfterFormat(rules);
- TargetFormat target = new PositiveDecimalFormat(symbols, properties);
- format.setTargetFormat(target);
- // TODO: integer-only format?
- if (MagnitudeMultiplier.useMagnitudeMultiplier(properties)) {
- canUseFastTrack = false;
- format.addBeforeFormat(MagnitudeMultiplier.getInstance(properties));
- }
- if (BigDecimalMultiplier.useMultiplier(properties)) {
- canUseFastTrack = false;
- format.addBeforeFormat(BigDecimalMultiplier.getInstance(properties));
- }
- if (MeasureFormat.useMeasureFormat(properties)) {
- canUseFastTrack = false;
- format.addBeforeFormat(MeasureFormat.getInstance(symbols, properties));
- }
- if (CurrencyFormat.useCurrency(properties)) {
- canUseFastTrack = false;
- if (CompactDecimalFormat.useCompactDecimalFormat(properties)) {
- format.addBeforeFormat(CompactDecimalFormat.getInstance(symbols, properties));
- } else if (ScientificFormat.useScientificNotation(properties)) {
- // TODO: Should the currency rounder or scientific rounder be used in this case?
- // For now, default to using the scientific rounder.
- format.addBeforeFormat(PositiveNegativeAffixFormat.getInstance(symbols, properties));
- format.addBeforeFormat(ScientificFormat.getInstance(symbols, properties));
- } else {
- format.addBeforeFormat(CurrencyFormat.getCurrencyRounder(symbols, properties));
- format.addBeforeFormat(CurrencyFormat.getCurrencyModifier(symbols, properties));
- }
- } else {
- if (CompactDecimalFormat.useCompactDecimalFormat(properties)) {
- canUseFastTrack = false;
- format.addBeforeFormat(CompactDecimalFormat.getInstance(symbols, properties));
- } else if (ScientificFormat.useScientificNotation(properties)) {
- canUseFastTrack = false;
- format.addBeforeFormat(PositiveNegativeAffixFormat.getInstance(symbols, properties));
- format.addBeforeFormat(ScientificFormat.getInstance(symbols, properties));
- } else {
- format.addBeforeFormat(PositiveNegativeAffixFormat.getInstance(symbols, properties));
- format.addBeforeFormat(RoundingFormat.getDefaultOrNoRounder(properties));
- }
- }
- if (PaddingFormat.usePadding(properties)) {
- canUseFastTrack = false;
- format.addAfterFormat(PaddingFormat.getInstance(properties));
- }
- if (canUseFastTrack) {
- return new Format.PositiveNegativeRounderTargetFormat(
- PositiveNegativeAffixFormat.getInstance(symbols, properties),
- RoundingFormat.getDefaultOrNoRounder(properties),
- target);
- } else {
- return format;
- }
- }
-
- public static String staticFormat(FormatQuantity input, Properties properties) {
- return staticFormat(input, properties, getSymbols());
- }
-
- public static String staticFormat(FormatQuantity input, Properties properties, Locale locale) {
- return staticFormat(input, properties, getSymbols(locale));
- }
-
- public static String staticFormat(FormatQuantity input, Properties properties, ULocale uLocale) {
- return staticFormat(input, properties, getSymbols(uLocale));
- }
-
- public static String staticFormat(FormatQuantity input, String pattern) {
- return staticFormat(input, getProperties(pattern), getSymbols());
- }
-
- public static String staticFormat(FormatQuantity input, String pattern, Locale locale) {
- return staticFormat(input, getProperties(pattern), getSymbols(locale));
- }
-
- public static String staticFormat(FormatQuantity input, String pattern, ULocale uLocale) {
- return staticFormat(input, getProperties(pattern), getSymbols(uLocale));
- }
-
- public static String staticFormat(
- FormatQuantity input, String pattern, DecimalFormatSymbols symbols) {
- return staticFormat(input, getProperties(pattern), symbols);
- }
-
- public static String staticFormat(
- FormatQuantity input, Properties properties, DecimalFormatSymbols symbols) {
- PluralRules rules = null;
- ModifierHolder mods = Format.threadLocalModifierHolder.get().clear();
- NumberStringBuilder sb = Format.threadLocalStringBuilder.get().clear();
- int length = 0;
-
- // Pre-processing
- if (!input.isNaN()) {
- if (MagnitudeMultiplier.useMagnitudeMultiplier(properties)) {
- MagnitudeMultiplier.getInstance(properties).before(input, mods, rules);
- }
- if (BigDecimalMultiplier.useMultiplier(properties)) {
- BigDecimalMultiplier.getInstance(properties).before(input, mods, rules);
- }
- if (MeasureFormat.useMeasureFormat(properties)) {
- rules = (rules != null) ? rules : getPluralRules(symbols.getULocale(), properties);
- MeasureFormat.getInstance(symbols, properties).before(input, mods, rules);
- }
- if (CompactDecimalFormat.useCompactDecimalFormat(properties)) {
- rules = (rules != null) ? rules : getPluralRules(symbols.getULocale(), properties);
- CompactDecimalFormat.apply(input, mods, rules, symbols, properties);
- } else if (CurrencyFormat.useCurrency(properties)) {
- rules = (rules != null) ? rules : getPluralRules(symbols.getULocale(), properties);
- CurrencyFormat.getCurrencyRounder(symbols, properties).before(input, mods, rules);
- CurrencyFormat.getCurrencyModifier(symbols, properties).before(input, mods, rules);
- } else if (ScientificFormat.useScientificNotation(properties)) {
- // TODO: Is it possible to combine significant digits with currency?
- PositiveNegativeAffixFormat.getInstance(symbols, properties).before(input, mods, rules);
- ScientificFormat.getInstance(symbols, properties).before(input, mods, rules);
- } else {
- PositiveNegativeAffixFormat.apply(input, mods, symbols, properties);
- RoundingFormat.getDefaultOrNoRounder(properties).before(input, mods, rules);
- }
- }
-
- // Primary format step
- length += new PositiveDecimalFormat(symbols, properties).target(input, sb, 0);
- length += mods.applyStrong(sb, 0, length);
-
- // Post-processing
- if (PaddingFormat.usePadding(properties)) {
- length += PaddingFormat.getInstance(properties).after(mods, sb, 0, length);
- }
- length += mods.applyAll(sb, 0, length);
-
- return sb.toString();
- }
-
- private static final ThreadLocal<Map<ULocale, DecimalFormatSymbols>> threadLocalSymbolsCache =
- new ThreadLocal<Map<ULocale, DecimalFormatSymbols>>() {
- @Override
- protected Map<ULocale, DecimalFormatSymbols> initialValue() {
- return new HashMap<ULocale, DecimalFormatSymbols>();
- }
- };
-
- private static DecimalFormatSymbols getSymbols() {
- ULocale uLocale = ULocale.getDefault();
- return getSymbols(uLocale);
- }
-
- private static DecimalFormatSymbols getSymbols(Locale locale) {
- ULocale uLocale = ULocale.forLocale(locale);
- return getSymbols(uLocale);
- }
-
- private static DecimalFormatSymbols getSymbols(ULocale uLocale) {
- if (uLocale == null) uLocale = ULocale.getDefault();
- DecimalFormatSymbols symbols = threadLocalSymbolsCache.get().get(uLocale);
- if (symbols == null) {
- symbols = DecimalFormatSymbols.getInstance(uLocale);
- threadLocalSymbolsCache.get().put(uLocale, symbols);
- }
- return symbols;
- }
-
- private static final ThreadLocal<Map<String, Properties>> threadLocalPropertiesCache =
- new ThreadLocal<Map<String, Properties>>() {
- @Override
- protected Map<String, Properties> initialValue() {
- return new HashMap<String, Properties>();
- }
- };
-
- private static Properties getProperties(String pattern) {
- if (pattern == null) pattern = "#";
- Properties properties = threadLocalPropertiesCache.get().get(pattern);
- if (properties == null) {
- properties = PatternString.parseToProperties(pattern);
- threadLocalPropertiesCache.get().put(pattern.intern(), properties);
- }
- return properties;
- }
-
- private static final ThreadLocal<Map<ULocale, PluralRules>> threadLocalRulesCache =
- new ThreadLocal<Map<ULocale, PluralRules>>() {
- @Override
- protected Map<ULocale, PluralRules> initialValue() {
- return new HashMap<ULocale, PluralRules>();
- }
- };
-
- private static PluralRules getPluralRules(ULocale uLocale, Properties properties) {
- if (properties.getPluralRules() != null) {
- return properties.getPluralRules();
- }
-
- // Backwards compatibility: CurrencyPluralInfo wraps its own copy of PluralRules
- if (properties.getCurrencyPluralInfo() != null) {
- return properties.getCurrencyPluralInfo().getPluralRules();
- }
-
- if (uLocale == null) uLocale = ULocale.getDefault();
- PluralRules rules = threadLocalRulesCache.get().get(uLocale);
- if (rules == null) {
- rules = PluralRules.forLocale(uLocale);
- threadLocalRulesCache.get().put(uLocale, rules);
- }
- return rules;
- }
-}
+++ /dev/null
-// © 2017 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html#License
-package com.ibm.icu.impl.number;
-
-/**
- * This is a small interface I made to assist with converting from a formatter pipeline object to a
- * pattern string. It allows classes to "export" themselves to a property bag, which in turn can be
- * passed to {@link PatternString#propertiesToString(Properties)} to generate the pattern string.
- *
- * <p>Depending on the new API we expose, this process might not be necessary if we persist the
- * property bag in the current DecimalFormat shim.
- */
-public interface Exportable {
- public void export(Properties properties);
-}
+++ /dev/null
-// © 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 java.text.AttributedCharacterIterator;
-import java.text.FieldPosition;
-import java.util.ArrayDeque;
-import java.util.Arrays;
-import java.util.Deque;
-
-import com.ibm.icu.text.PluralRules;
-
-// TODO: Get a better name for this base class.
-public abstract class Format {
-
- protected static final ThreadLocal<NumberStringBuilder> threadLocalStringBuilder =
- new ThreadLocal<NumberStringBuilder>() {
- @Override
- protected NumberStringBuilder initialValue() {
- return new NumberStringBuilder();
- }
- };
-
- protected static final ThreadLocal<ModifierHolder> threadLocalModifierHolder =
- new ThreadLocal<ModifierHolder>() {
- @Override
- protected ModifierHolder initialValue() {
- return new ModifierHolder();
- }
- };
-
- public String format(FormatQuantity... inputs) {
- // Setup
- Deque<FormatQuantity> inputDeque = new ArrayDeque<FormatQuantity>();
- inputDeque.addAll(Arrays.asList(inputs));
- ModifierHolder modDeque = threadLocalModifierHolder.get().clear();
- NumberStringBuilder sb = threadLocalStringBuilder.get().clear();
-
- // Primary "recursion" step, calling the implementation's process method
- int length = process(inputDeque, modDeque, sb, 0);
-
- // Resolve remaining affixes
- modDeque.applyAll(sb, 0, length);
- return sb.toString();
- }
-
- /** A Format that works on only one number. */
- public abstract static class SingularFormat extends Format implements Exportable {
-
- public String format(FormatQuantity input) {
- NumberStringBuilder sb = formatToStringBuilder(input);
- return sb.toString();
- }
-
- public void format(FormatQuantity input, StringBuffer output) {
- NumberStringBuilder sb = formatToStringBuilder(input);
- output.append(sb);
- }
-
- public String format(FormatQuantity input, FieldPosition fp) {
- NumberStringBuilder sb = formatToStringBuilder(input);
- sb.populateFieldPosition(fp, 0);
- return sb.toString();
- }
-
- public void format(FormatQuantity input, StringBuffer output, FieldPosition fp) {
- NumberStringBuilder sb = formatToStringBuilder(input);
- sb.populateFieldPosition(fp, output.length());
- output.append(sb);
- }
-
- public AttributedCharacterIterator formatToCharacterIterator(FormatQuantity input) {
- NumberStringBuilder sb = formatToStringBuilder(input);
- return sb.getIterator();
- }
-
- private NumberStringBuilder formatToStringBuilder(FormatQuantity input) {
- // Setup
- ModifierHolder modDeque = threadLocalModifierHolder.get().clear();
- NumberStringBuilder sb = threadLocalStringBuilder.get().clear();
-
- // Primary "recursion" step, calling the implementation's process method
- int length = process(input, modDeque, sb, 0);
-
- // Resolve remaining affixes
- length += modDeque.applyAll(sb, 0, length);
- return sb;
- }
-
- @Override
- public int process(
- Deque<FormatQuantity> input,
- ModifierHolder mods,
- NumberStringBuilder string,
- int startIndex) {
- return process(input.removeFirst(), mods, string, startIndex);
- }
-
- public abstract int process(
- FormatQuantity input, ModifierHolder mods, NumberStringBuilder string, int startIndex);
- }
-
- public static class BeforeTargetAfterFormat extends SingularFormat {
- // The formatters are kept as individual fields to avoid extra object creation overhead.
- private BeforeFormat before1 = null;
- private BeforeFormat before2 = null;
- private BeforeFormat before3 = null;
- private TargetFormat target = null;
- private AfterFormat after1 = null;
- private AfterFormat after2 = null;
- private AfterFormat after3 = null;
- private final PluralRules rules;
-
- public BeforeTargetAfterFormat(PluralRules rules) {
- this.rules = rules;
- }
-
- public void addBeforeFormat(BeforeFormat before) {
- if (before1 == null) {
- before1 = before;
- } else if (before2 == null) {
- before2 = before;
- } else if (before3 == null) {
- before3 = before;
- } else {
- throw new IllegalArgumentException("Only three BeforeFormats are allowed at a time");
- }
- }
-
- public void setTargetFormat(TargetFormat target) {
- this.target = target;
- }
-
- public void addAfterFormat(AfterFormat after) {
- if (after1 == null) {
- after1 = after;
- } else if (after2 == null) {
- after2 = after;
- } else if (after3 == null) {
- after3 = after;
- } else {
- throw new IllegalArgumentException("Only three AfterFormats are allowed at a time");
- }
- }
-
- @Override
- public String format(FormatQuantity input) {
- ModifierHolder mods = threadLocalModifierHolder.get().clear();
- NumberStringBuilder sb = threadLocalStringBuilder.get().clear();
- int length = process(input, mods, sb, 0);
- mods.applyAll(sb, 0, length);
- return sb.toString();
- }
-
- @Override
- public int process(
- FormatQuantity input, ModifierHolder mods, NumberStringBuilder string, int startIndex) {
- // Special case: modifiers are skipped for NaN
- int length = 0;
- if (!input.isNaN()) {
- if (before1 != null) {
- before1.before(input, mods, rules);
- }
- if (before2 != null) {
- before2.before(input, mods, rules);
- }
- if (before3 != null) {
- before3.before(input, mods, rules);
- }
- }
- length = target.target(input, string, startIndex);
- length += mods.applyStrong(string, startIndex, startIndex + length);
- if (after1 != null) {
- length += after1.after(mods, string, startIndex, startIndex + length);
- }
- if (after2 != null) {
- length += after2.after(mods, string, startIndex, startIndex + length);
- }
- if (after3 != null) {
- length += after3.after(mods, string, startIndex, startIndex + length);
- }
- return length;
- }
-
- @Override
- public void export(Properties properties) {
- if (before1 != null) {
- before1.export(properties);
- }
- if (before2 != null) {
- before2.export(properties);
- }
- if (before3 != null) {
- before3.export(properties);
- }
- target.export(properties);
- if (after1 != null) {
- after1.export(properties);
- }
- if (after2 != null) {
- after2.export(properties);
- }
- if (after3 != null) {
- after3.export(properties);
- }
- }
- }
-
- public static class PositiveNegativeRounderTargetFormat extends SingularFormat {
- private final Modifier.PositiveNegativeModifier positiveNegative;
- private final Rounder rounder;
- private final TargetFormat target;
-
- public PositiveNegativeRounderTargetFormat(
- Modifier.PositiveNegativeModifier positiveNegative, Rounder rounder, TargetFormat target) {
- this.positiveNegative = positiveNegative;
- this.rounder = rounder;
- this.target = target;
- }
-
- @Override
- public String format(FormatQuantity input) {
- NumberStringBuilder sb = threadLocalStringBuilder.get().clear();
- process(input, null, sb, 0);
- return sb.toString();
- }
-
- @Override
- public int process(
- FormatQuantity input, ModifierHolder mods, NumberStringBuilder string, int startIndex) {
- // Special case: modifiers are skipped for NaN
- Modifier mod = null;
- rounder.apply(input);
- if (!input.isNaN() && positiveNegative != null) {
- mod = positiveNegative.getModifier(input.isNegative());
- }
- int length = target.target(input, string, startIndex);
- if (mod != null) {
- length += mod.apply(string, 0, length);
- }
- return length;
- }
-
- @Override
- public void export(Properties properties) {
- rounder.export(properties);
- positiveNegative.export(properties);
- target.export(properties);
- }
- }
-
- public abstract static class BeforeFormat implements Exportable {
- protected abstract void before(FormatQuantity input, ModifierHolder mods);
-
- @SuppressWarnings("unused")
- public void before(FormatQuantity input, ModifierHolder mods, PluralRules rules) {
- before(input, mods);
- }
- }
-
- public static interface TargetFormat extends Exportable {
- public abstract int target(FormatQuantity input, NumberStringBuilder string, int startIndex);
- }
-
- public static interface AfterFormat extends Exportable {
- public abstract int after(
- ModifierHolder mods, NumberStringBuilder string, int leftIndex, int rightIndex);
- }
-
- // Instead of Dequeue<BigDecimal>, it could be Deque<Quantity> where
- // we control the API of Quantity
- public abstract int process(
- Deque<FormatQuantity> inputs,
- ModifierHolder outputMods,
- NumberStringBuilder outputString,
- int startIndex);
-}
import java.math.BigDecimal;
import java.math.MathContext;
+import java.text.FieldPosition;
import com.ibm.icu.impl.StandardPlural;
import com.ibm.icu.text.PluralRules;
+import com.ibm.icu.text.UFieldPosition;
/**
* An interface representing a number to be processed by the decimal formatting pipeline. Includes
/** This method is for internal testing only. */
public long getPositionFingerprint();
+
+ /**
+ * If the given {@link FieldPosition} is a {@link UFieldPosition}, populates it with the fraction
+ * length and fraction long value. If the argument is not a {@link UFieldPosition}, nothing
+ * happens.
+ *
+ * @param fp The {@link UFieldPosition} to populate.
+ */
+ public void populateUFieldPosition(FieldPosition fp);
}
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
+import java.text.FieldPosition;
import com.ibm.icu.impl.StandardPlural;
import com.ibm.icu.text.PluralRules;
import com.ibm.icu.text.PluralRules.Operand;
+import com.ibm.icu.text.UFieldPosition;
/**
* This is an older implementation of FormatQuantity. A newer, faster implementation is
return i;
}
}
+
+ @Override
+ public void populateUFieldPosition(FieldPosition fp) {
+ if (fp instanceof UFieldPosition) {
+ ((UFieldPosition) fp)
+ .setFractionDigits((int) getPluralOperand(Operand.v), (long) getPluralOperand(Operand.f));
+ }
+ }
}
}
}
- /**
- * If the given {@link FieldPosition} is a {@link UFieldPosition}, populates it with the fraction
- * length and fraction long value. If the argument is not a {@link UFieldPosition}, nothing
- * happens.
- *
- * @param fp The {@link UFieldPosition} to populate.
- */
+ @Override
public void populateUFieldPosition(FieldPosition fp) {
if (fp instanceof UFieldPosition) {
((UFieldPosition) fp)
+++ /dev/null
-// © 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 java.math.BigDecimal;
-import java.math.BigInteger;
-
-/** @author sffc */
-public class FormatQuantitySelector {
- public static FormatQuantityBCD from(int input) {
- return new FormatQuantity4(input);
- }
-
- public static FormatQuantityBCD from(long input) {
- return new FormatQuantity4(input);
- }
-
- public static FormatQuantityBCD from(double input) {
- return new FormatQuantity4(input);
- }
-
- public static FormatQuantityBCD from(BigInteger input) {
- return new FormatQuantity4(input);
- }
-
- public static FormatQuantityBCD from(BigDecimal input) {
- return new FormatQuantity4(input);
- }
-
- public static FormatQuantityBCD from(com.ibm.icu.math.BigDecimal input) {
- return from(input.toBigDecimal());
- }
-
- public static FormatQuantityBCD from(Number number) {
- if (number instanceof Long) {
- return from(number.longValue());
- } else if (number instanceof Integer) {
- return from(number.intValue());
- } else if (number instanceof Double) {
- return from(number.doubleValue());
- } else if (number instanceof BigInteger) {
- return from((BigInteger) number);
- } else if (number instanceof BigDecimal) {
- return from((BigDecimal) number);
- } else if (number instanceof com.ibm.icu.math.BigDecimal) {
- return from((com.ibm.icu.math.BigDecimal) number);
- } else {
- throw new IllegalArgumentException(
- "Number is of an unsupported type: " + number.getClass().getName());
- }
- }
-}
// License & terms of use: http://www.unicode.org/copyright.html#License
package com.ibm.icu.impl.number;
-import com.ibm.icu.impl.number.formatters.PaddingFormat.PadPosition;
+import com.ibm.icu.impl.number.ThingsNeedingNewHome.PadPosition;
import newapi.impl.AffixPatternProvider;
* class implementing {@link PositiveNegativeModifier} is not necessarily a {@link Modifier}
* itself. Rather, it returns a {@link Modifier} when {@link #getModifier} is called.
*/
- public static interface PositiveNegativeModifier extends Exportable {
+ public static interface PositiveNegativeModifier {
/**
* Converts this {@link PositiveNegativeModifier} to a {@link Modifier} given the negative sign.
*
* necessarily a {@link Modifier} itself. Rather, it returns a {@link Modifier} when {@link
* #getModifier} is called.
*/
- public static interface PositiveNegativePluralModifier extends Exportable {
+ public static interface PositiveNegativePluralModifier {
/**
* Converts this {@link PositiveNegativePluralModifier} to a {@link Modifier} given the negative
* sign and the standard plural.
* <p>Implements {@link PositiveNegativeModifier} only so that instances of this class can be used
* when a {@link PositiveNegativeModifier} is required.
*/
- public abstract static class BaseModifier extends Format.BeforeFormat
- implements Modifier, PositiveNegativeModifier {
-
- @Override
- public void before(FormatQuantity input, ModifierHolder mods) {
- mods.add(this);
- }
+ public abstract static class BaseModifier implements Modifier, PositiveNegativeModifier {
@Override
public Modifier getModifier(boolean isNegative) {
+++ /dev/null
-// © 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 java.util.ArrayDeque;
-
-public class ModifierHolder {
- private ArrayDeque<Modifier> mods = new ArrayDeque<Modifier>();
-
- // Using five separate fields instead of the ArrayDeque saves about 10ns at the expense of
- // worse code.
- // TODO: Decide which implementation to use.
-
- // private Modifier mod1 = null;
- // private Modifier mod2 = null;
- // private Modifier mod3 = null;
- // private Modifier mod4 = null;
- // private Modifier mod5 = null;
-
- public ModifierHolder createCopy() {
- ModifierHolder copy = new ModifierHolder();
- copy.mods.addAll(mods);
- return copy;
- }
-
- public ModifierHolder clear() {
- // mod1 = null;
- // mod2 = null;
- // mod3 = null;
- // mod4 = null;
- // mod5 = null;
- mods.clear();
- return this;
- }
-
- public void add(Modifier modifier) {
- // if (mod1 == null) {
- // mod1 = modifier;
- // } else if (mod2 == null) {
- // mod2 = modifier;
- // } else if (mod3 == null) {
- // mod3 = modifier;
- // } else if (mod4 == null) {
- // mod4 = modifier;
- // } else if (mod5 == null) {
- // mod5 = modifier;
- // } else {
- // throw new IndexOutOfBoundsException();
- // }
- if (modifier != null) mods.addFirst(modifier);
- }
-
- public Modifier peekLast() {
- return mods.peekLast();
- }
-
- public Modifier removeLast() {
- return mods.removeLast();
- }
-
- public int applyAll(NumberStringBuilder string, int leftIndex, int rightIndex) {
- int addedLength = 0;
- // if (mod5 != null) {
- // addedLength += mod5.apply(string, leftIndex, rightIndex + addedLength);
- // mod5 = null;
- // }
- // if (mod4 != null) {
- // addedLength += mod4.apply(string, leftIndex, rightIndex + addedLength);
- // mod4 = null;
- // }
- // if (mod3 != null) {
- // addedLength += mod3.apply(string, leftIndex, rightIndex + addedLength);
- // mod3 = null;
- // }
- // if (mod2 != null) {
- // addedLength += mod2.apply(string, leftIndex, rightIndex + addedLength);
- // mod2 = null;
- // }
- // if (mod1 != null) {
- // addedLength += mod1.apply(string, leftIndex, rightIndex + addedLength);
- // mod1 = null;
- // }
- while (!mods.isEmpty()) {
- Modifier mod = mods.removeFirst();
- addedLength += mod.apply(string, leftIndex, rightIndex + addedLength);
- }
- return addedLength;
- }
-
- public int applyStrong(NumberStringBuilder string, int leftIndex, int rightIndex) {
- int addedLength = 0;
- while (!mods.isEmpty() && mods.peekFirst().isStrong()) {
- Modifier mod = mods.removeFirst();
- addedLength += mod.apply(string, leftIndex, rightIndex + addedLength);
- }
- return addedLength;
- }
-}
+++ /dev/null
-// © 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.number.Modifier.AffixModifier;
-import com.ibm.icu.impl.number.formatters.CompactDecimalFormat;
-import com.ibm.icu.impl.number.formatters.PositiveNegativeAffixFormat;
-import com.ibm.icu.impl.number.formatters.PositiveNegativeAffixFormat.IProperties;
-import com.ibm.icu.impl.number.modifiers.ConstantAffixModifier;
-import com.ibm.icu.impl.number.modifiers.ConstantMultiFieldModifier;
-import com.ibm.icu.text.DecimalFormatSymbols;
-import com.ibm.icu.text.NumberFormat.Field;
-
-/**
- * A class to convert from a bag of prefix/suffix properties into a positive and negative {@link
- * Modifier}. This is a standard implementation used by {@link PositiveNegativeAffixFormat}, {@link
- * CompactDecimalFormat}, {@link Parse}, and others.
- *
- * <p>This class is is intended to be an efficient generator for instances of Modifier by a single
- * thread during construction of a formatter or during static formatting. It uses internal caching
- * to avoid creating new Modifier objects when possible. It is NOT THREAD SAFE and NOT IMMUTABLE.
- *
- * <p>The thread-local instance of this class provided by {@link #getThreadLocalInstance} should be
- * used in most cases instead of constructing a new instance of the object.
- *
- * <p>This class also handles the logic of assigning positive signs, negative signs, and currency
- * signs according to the LDML specification.
- */
-public class PNAffixGenerator {
- public static class Result {
- public AffixModifier positive = null;
- public AffixModifier negative = null;
- }
-
- protected static final ThreadLocal<PNAffixGenerator> threadLocalInstance =
- new ThreadLocal<PNAffixGenerator>() {
- @Override
- protected PNAffixGenerator initialValue() {
- return new PNAffixGenerator();
- }
- };
-
- public static PNAffixGenerator getThreadLocalInstance() {
- return threadLocalInstance.get();
- }
-
- // These instances are used internally and cached to avoid object creation. The resultInstance
- // also serves as a 1-element cache to avoid creating objects when subsequent calls have
- // identical prefixes and suffixes. This happens, for example, when consuming CDF data.
- private Result resultInstance = new Result();
- private NumberStringBuilder sb1 = new NumberStringBuilder();
- private NumberStringBuilder sb2 = new NumberStringBuilder();
- private NumberStringBuilder sb3 = new NumberStringBuilder();
- private NumberStringBuilder sb4 = new NumberStringBuilder();
- private NumberStringBuilder sb5 = new NumberStringBuilder();
- private NumberStringBuilder sb6 = new NumberStringBuilder();
-
- /**
- * Generates modifiers using default currency symbols.
- *
- * @param symbols The symbols to interpolate for minus, plus, percent, permille, and currency.
- * @param properties The bag of properties to convert.
- * @return The positive and negative {@link Modifier}.
- */
- public Result getModifiers(
- DecimalFormatSymbols symbols, PositiveNegativeAffixFormat.IProperties properties) {
- // If this method is used, the user doesn't care about currencies. Default the currency symbols
- // to the information we can get from the DecimalFormatSymbols instance.
- return getModifiers(
- symbols,
- symbols.getCurrencySymbol(),
- symbols.getInternationalCurrencySymbol(),
- symbols.getCurrencySymbol(),
- properties);
- }
-
- /**
- * Generates modifiers using the specified currency symbol for all three lengths of currency
- * placeholders in the pattern string.
- *
- * @param symbols The symbols to interpolate for minus, plus, percent, and permille.
- * @param currencySymbol The currency symbol.
- * @param properties The bag of properties to convert.
- * @return The positive and negative {@link Modifier}.
- */
- public Result getModifiers(
- DecimalFormatSymbols symbols,
- String currencySymbol,
- PositiveNegativeAffixFormat.IProperties properties) {
- // If this method is used, the user doesn't cares about currencies but doesn't care about
- // supporting all three sizes of currency placeholders. Use the one provided string for all
- // three sizes of placeholders.
- return getModifiers(symbols, currencySymbol, currencySymbol, currencySymbol, properties);
- }
-
- /**
- * Generates modifiers using the three specified strings to replace the three lengths of currency
- * placeholders: "¤", "¤¤", and "¤¤¤".
- *
- * @param symbols The symbols to interpolate for minus, plus, percent, and permille.
- * @param curr1 The string to replace "¤".
- * @param curr2 The string to replace "¤¤".
- * @param curr3 The string to replace "¤¤¤".
- * @param properties The bag of properties to convert.
- * @return The positive and negative {@link Modifier}.
- */
- public Result getModifiers(
- DecimalFormatSymbols symbols,
- String curr1,
- String curr2,
- String curr3,
- PositiveNegativeAffixFormat.IProperties properties) {
-
- // Use a different code path for handling affixes with "always show plus sign"
- if (properties.getSignAlwaysShown()) {
- return getModifiersWithPlusSign(symbols, curr1, curr2, curr3, properties);
- }
-
- String ppp = properties.getPositivePrefixPattern();
- String psp = properties.getPositiveSuffixPattern();
- String npp = properties.getNegativePrefixPattern();
- String nsp = properties.getNegativeSuffixPattern();
-
- // Set sb1/sb2 to the positive prefix/suffix.
- sb1.clear();
- sb2.clear();
- AffixPatternUtils.unescape(ppp, symbols, curr1, curr2, curr3, null, sb1);
- AffixPatternUtils.unescape(psp, symbols, curr1, curr2, curr3, null, sb2);
- setPositiveResult(sb1, sb2, properties);
-
- // Set sb1/sb2 to the negative prefix/suffix.
- if (npp == null && nsp == null) {
- // Negative prefix defaults to positive prefix prepended with the minus sign.
- // Negative suffix defaults to positive suffix.
- sb1.insert(0, symbols.getMinusSignString(), Field.SIGN);
- } else {
- sb1.clear();
- sb2.clear();
- AffixPatternUtils.unescape(npp, symbols, curr1, curr2, curr3, null, sb1);
- AffixPatternUtils.unescape(nsp, symbols, curr1, curr2, curr3, null, sb2);
- }
- setNegativeResult(sb1, sb2, properties);
-
- return resultInstance;
- }
-
- private Result getModifiersWithPlusSign(
- DecimalFormatSymbols symbols,
- String curr1,
- String curr2,
- String curr3,
- IProperties properties) {
-
- String ppp = properties.getPositivePrefixPattern();
- String psp = properties.getPositiveSuffixPattern();
- String npp = properties.getNegativePrefixPattern();
- String nsp = properties.getNegativeSuffixPattern();
-
- // There are three cases, listed below with their expected outcomes.
- // TODO: Should we handle the cases when the positive subpattern has a '+' already?
- //
- // 1) No negative subpattern.
- // Positive => Positive subpattern prepended with '+'
- // Negative => Positive subpattern prepended with '-'
- // 2) Negative subpattern does not have '-'.
- // Positive => Positive subpattern prepended with '+'
- // Negative => Negative subpattern
- // 3) Negative subpattern has '-'.
- // Positive => Negative subpattern with '+' substituted for '-'
- // Negative => Negative subpattern
-
- if (npp != null || nsp != null) {
- // Case 2 or Case 3
- sb1.clear();
- sb2.clear();
- sb3.clear();
- sb4.clear();
- AffixPatternUtils.unescape(npp, symbols, curr1, curr2, curr3, null, sb1);
- AffixPatternUtils.unescape(nsp, symbols, curr1, curr2, curr3, null, sb2);
- AffixPatternUtils.unescape(
- npp, symbols, curr1, curr2, curr3, symbols.getPlusSignString(), sb3);
- AffixPatternUtils.unescape(
- nsp, symbols, curr1, curr2, curr3, symbols.getPlusSignString(), sb4);
- if (!charSequenceEquals(sb1, sb3) || !charSequenceEquals(sb2, sb4)) {
- // Case 3. The plus sign substitution was successful.
- setPositiveResult(sb3, sb4, properties);
- setNegativeResult(sb1, sb2, properties);
- return resultInstance;
- } else {
- // Case 2. There was no minus sign. Set the negative result and fall through.
- setNegativeResult(sb1, sb2, properties);
- }
- }
-
- // Case 1 or 2. Set sb1/sb2 to the positive prefix/suffix.
- sb1.clear();
- sb2.clear();
- AffixPatternUtils.unescape(ppp, symbols, curr1, curr2, curr3, null, sb1);
- AffixPatternUtils.unescape(psp, symbols, curr1, curr2, curr3, null, sb2);
-
- if (npp == null && nsp == null) {
- // Case 1. Compute the negative result from the positive subpattern.
- sb3.clear();
- sb3.append(symbols.getMinusSignString(), Field.SIGN);
- sb3.append(sb1);
- setNegativeResult(sb3, sb2, properties);
- }
-
- // Case 1 or 2. Prepend a '+' sign to the positive prefix.
- sb1.insert(0, symbols.getPlusSignString(), Field.SIGN);
- setPositiveResult(sb1, sb2, properties);
-
- return resultInstance;
- }
-
- private void setPositiveResult(
- NumberStringBuilder prefix, NumberStringBuilder suffix, IProperties properties) {
- // Override with custom affixes. We need to put these into NumberStringBuilders so that they
- // have the same datatype as the incoming prefix and suffix (important when testing for field
- // equality in contentEquals).
- // TODO: It is a little inefficient that we copy String -> NumberStringBuilder -> Modifier.
- // Consider re-working the logic so that fewer copies are required.
- String _prefix = properties.getPositivePrefix();
- String _suffix = properties.getPositiveSuffix();
- if (_prefix != null) {
- prefix = sb5.clear();
- prefix.append(_prefix, null);
- }
- if (_suffix != null) {
- suffix = sb6.clear();
- suffix.append(_suffix, null);
- }
- if (prefix.length() == 0 && suffix.length() == 0) {
- resultInstance.positive = ConstantAffixModifier.EMPTY;
- return;
- }
- if (resultInstance.positive != null
- && (resultInstance.positive instanceof ConstantMultiFieldModifier)
- && ((ConstantMultiFieldModifier) resultInstance.positive).contentEquals(prefix, suffix)) {
- // Use the cached modifier
- return;
- }
- resultInstance.positive = new ConstantMultiFieldModifier(prefix, suffix, false);
- }
-
- private void setNegativeResult(
- NumberStringBuilder prefix, NumberStringBuilder suffix, IProperties properties) {
- String _prefix = properties.getNegativePrefix();
- String _suffix = properties.getNegativeSuffix();
- if (_prefix != null) {
- prefix = sb5.clear();
- prefix.append(_prefix, null);
- }
- if (_suffix != null) {
- suffix = sb6.clear();
- suffix.append(_suffix, null);
- }
- if (prefix.length() == 0 && suffix.length() == 0) {
- resultInstance.negative = ConstantAffixModifier.EMPTY;
- return;
- }
- if (resultInstance.negative != null
- && (resultInstance.negative instanceof ConstantMultiFieldModifier)
- && ((ConstantMultiFieldModifier) resultInstance.negative).contentEquals(prefix, suffix)) {
- // Use the cached modifier
- return;
- }
- resultInstance.negative = new ConstantMultiFieldModifier(prefix, suffix, false);
- }
-
- /** A null-safe equals method for CharSequences. */
- private static boolean charSequenceEquals(CharSequence a, CharSequence b) {
- if (a == b) return true;
- if (a == null || b == null) return false;
- if (a.length() != b.length()) return false;
- for (int i = 0; i < a.length(); i++) {
- if (a.charAt(i) != b.charAt(i)) return false;
- }
- return true;
- }
-}
import com.ibm.icu.impl.StandardPlural;
import com.ibm.icu.impl.TextTrieMap;
-import com.ibm.icu.impl.number.formatters.BigDecimalMultiplier;
-import com.ibm.icu.impl.number.formatters.CurrencyFormat;
-import com.ibm.icu.impl.number.formatters.MagnitudeMultiplier;
-import com.ibm.icu.impl.number.formatters.PaddingFormat;
-import com.ibm.icu.impl.number.formatters.PositiveDecimalFormat;
-import com.ibm.icu.impl.number.formatters.PositiveNegativeAffixFormat;
-import com.ibm.icu.impl.number.formatters.ScientificFormat;
import com.ibm.icu.lang.UCharacter;
import com.ibm.icu.text.CurrencyPluralInfo;
import com.ibm.icu.text.DecimalFormatSymbols;
FAST,
}
- /** The set of properties required for {@link Parse}. Accepts a {@link Properties} object. */
- public static interface IProperties
- extends PositiveNegativeAffixFormat.IProperties,
- PaddingFormat.IProperties,
- CurrencyFormat.ICurrencyProperties,
- BigDecimalMultiplier.IProperties,
- MagnitudeMultiplier.IProperties,
- PositiveDecimalFormat.IProperties,
- ScientificFormat.IProperties {
-
- boolean DEFAULT_PARSE_INTEGER_ONLY = false;
-
- /** @see #setParseIntegerOnly */
- public boolean getParseIntegerOnly();
-
- /**
- * Whether to ignore the fractional part of numbers. For example, parses "123.4" to "123"
- * instead of "123.4".
- *
- * @param parseIntegerOnly true to parse integers only; false to parse integers with their
- * fraction parts
- * @return The property bag, for chaining.
- */
- public IProperties setParseIntegerOnly(boolean parseIntegerOnly);
-
- boolean DEFAULT_PARSE_NO_EXPONENT = false;
-
- /** @see #setParseNoExponent */
- public boolean getParseNoExponent();
-
- /**
- * Whether to ignore the exponential part of numbers. For example, parses "123E4" to "123"
- * instead of "1230000".
- *
- * @param parseIgnoreExponent true to ignore exponents; false to parse them.
- * @return The property bag, for chaining.
- */
- public IProperties setParseNoExponent(boolean parseIgnoreExponent);
-
- boolean DEFAULT_DECIMAL_PATTERN_MATCH_REQUIRED = false;
-
- /** @see #setDecimalPatternMatchRequired */
- public boolean getDecimalPatternMatchRequired();
-
- /**
- * Whether to require that the presence of decimal point matches the pattern. If a decimal point
- * is not present, but the pattern contained a decimal point, parse will not succeed: null will
- * be returned from <code>parse()</code>, and an error index will be set in the {@link
- * ParsePosition}.
- *
- * @param decimalPatternMatchRequired true to set an error if decimal is not present
- * @return The property bag, for chaining.
- */
- public IProperties setDecimalPatternMatchRequired(boolean decimalPatternMatchRequired);
-
- ParseMode DEFAULT_PARSE_MODE = null;
-
- /** @see #setParseMode */
- public ParseMode getParseMode();
-
- /**
- * Controls certain rules for how strict this parser is when reading strings. See {@link
- * ParseMode#LENIENT} and {@link ParseMode#STRICT}.
- *
- * @param parseMode Either {@link ParseMode#LENIENT} or {@link ParseMode#STRICT}.
- * @return The property bag, for chaining.
- */
- public IProperties setParseMode(ParseMode parseMode);
-
- boolean DEFAULT_PARSE_TO_BIG_DECIMAL = false;
-
- /** @see #setParseToBigDecimal */
- public boolean getParseToBigDecimal();
-
- /**
- * Whether to always return a BigDecimal from {@link Parse#parse} and all other parse methods.
- * By default, a Long or a BigInteger are returned when possible.
- *
- * @param parseToBigDecimal true to always return a BigDecimal; false to return a Long or a
- * BigInteger when possible.
- * @return The property bag, for chaining.
- */
- public IProperties setParseToBigDecimal(boolean parseToBigDecimal);
-
- boolean DEFAULT_PARSE_CASE_SENSITIVE = false;
-
- /** @see #setParseCaseSensitive */
- public boolean getParseCaseSensitive();
-
- /**
- * Whether to require cases to match when parsing strings; default is true. Case sensitivity
- * applies to prefixes, suffixes, the exponent separator, the symbol "NaN", and the infinity
- * symbol. Grouping separators, decimal separators, and padding are always case-sensitive.
- * Currencies are always case-insensitive.
- *
- * <p>This setting is ignored in fast mode. In fast mode, strings are always compared in a
- * case-sensitive way.
- *
- * @param parseCaseSensitive true to be case-sensitive when parsing; false to allow any case.
- * @return The property bag, for chaining.
- */
- public IProperties setParseCaseSensitive(boolean parseCaseSensitive);
-
- GroupingMode DEFAULT_PARSE_GROUPING_MODE = null;
-
- /** @see #setParseGroupingMode */
- public GroupingMode getParseGroupingMode();
-
- /**
- * Sets the strategy used during parsing when a code point needs to be interpreted as either a
- * decimal separator or a grouping separator.
- *
- * <p>The comma, period, space, and apostrophe have different meanings in different locales. For
- * example, in <em>en-US</em> and most American locales, the period is used as a decimal
- * separator, but in <em>es-PY</em> and most European locales, it is used as a grouping
- * separator.
- *
- * <p>Suppose you are in <em>fr-FR</em> the parser encounters the string "1.234". In
- * <em>fr-FR</em>, the grouping is a space and the decimal is a comma. The <em>grouping
- * mode</em> is a mechanism to let you specify whether to accept the string as 1234
- * (GroupingMode.DEFAULT) or whether to reject it since the separators don't match
- * (GroupingMode.RESTRICTED).
- *
- * <p>When resolving grouping separators, it is the <em>equivalence class</em> of separators
- * that is considered. For example, a period is seen as equal to a fixed set of other
- * period-like characters.
- *
- * @param parseGroupingMode The {@link GroupingMode} to use; either DEFAULT or RESTRICTED.
- * @return The property bag, for chaining.
- */
- public IProperties setParseGroupingMode(GroupingMode parseGroupingMode);
- }
-
/**
* An enum containing the choices for strategy in parsing when choosing between grouping and
* decimal separators.
}
/**
- * @see Parse#parse(String, ParsePosition, ParseMode, boolean, boolean, IProperties,
+ * @see Parse#parse(String, ParsePosition, ParseMode, boolean, boolean, Properties,
* DecimalFormatSymbols)
*/
private static enum StateName {
*
* @return The Number. Never null.
*/
- Number toNumber(IProperties properties) {
+ Number toNumber(Properties properties) {
// Check for NaN, infinity, and -0.0
if (sawNaN) {
return Double.NaN;
*
* @return The CurrencyAmount. Never null.
*/
- public CurrencyAmount toCurrencyAmount(IProperties properties) {
+ public CurrencyAmount toCurrencyAmount(Properties properties) {
assert isoCode != null;
Number number = toNumber(properties);
Currency currency = Currency.getInstance(isoCode);
int prevLength;
// Properties and Symbols memory:
- IProperties properties;
+ Properties properties;
DecimalFormatSymbols symbols;
ParseMode mode;
boolean caseSensitive;
@Override
public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append("<ParseState mode:");
- sb.append(mode);
- sb.append(" caseSensitive:");
- sb.append(caseSensitive);
- sb.append(" parseCurrency:");
- sb.append(parseCurrency);
- sb.append(" groupingMode:");
- sb.append(groupingMode);
- sb.append(" decimalCps:");
- sb.append((char)decimalCp1);
- sb.append((char)decimalCp2);
- sb.append(" groupingCps:");
- sb.append((char)groupingCp1);
- sb.append((char)groupingCp2);
- sb.append(" affixes:");
- sb.append(affixHolders);
- sb.append(">");
- return sb.toString();
+ StringBuilder sb = new StringBuilder();
+ sb.append("<ParseState mode:");
+ sb.append(mode);
+ sb.append(" caseSensitive:");
+ sb.append(caseSensitive);
+ sb.append(" parseCurrency:");
+ sb.append(parseCurrency);
+ sb.append(" groupingMode:");
+ sb.append(groupingMode);
+ sb.append(" decimalCps:");
+ sb.append((char) decimalCp1);
+ sb.append((char) decimalCp2);
+ sb.append(" groupingCps:");
+ sb.append((char) groupingCp1);
+ sb.append((char) groupingCp2);
+ sb.append(" affixes:");
+ sb.append(affixHolders);
+ sb.append(">");
+ return sb.toString();
}
}
static final AffixHolder EMPTY_POSITIVE = new AffixHolder("", "", true, false);
static final AffixHolder EMPTY_NEGATIVE = new AffixHolder("", "", true, true);
- static void addToState(ParserState state, IProperties properties) {
+ static void addToState(ParserState state, Properties properties) {
AffixHolder pp = fromPropertiesPositivePattern(properties);
AffixHolder np = fromPropertiesNegativePattern(properties);
AffixHolder ps = fromPropertiesPositiveString(properties);
if (ns != null) state.affixHolders.add(ns);
}
- static AffixHolder fromPropertiesPositivePattern(IProperties properties) {
+ static AffixHolder fromPropertiesPositivePattern(Properties properties) {
String ppp = properties.getPositivePrefixPattern();
String psp = properties.getPositiveSuffixPattern();
if (properties.getSignAlwaysShown()) {
- // TODO: This logic is somewhat duplicated from PNAffixGenerator.
+ // TODO: This logic is somewhat duplicated from MurkyModifier.
boolean foundSign = false;
String npp = properties.getNegativePrefixPattern();
String nsp = properties.getNegativeSuffixPattern();
return getInstance(ppp, psp, false, false);
}
- static AffixHolder fromPropertiesNegativePattern(IProperties properties) {
+ static AffixHolder fromPropertiesNegativePattern(Properties properties) {
String npp = properties.getNegativePrefixPattern();
String nsp = properties.getNegativeSuffixPattern();
if (npp == null && nsp == null) {
return getInstance(npp, nsp, false, true);
}
- static AffixHolder fromPropertiesPositiveString(IProperties properties) {
+ static AffixHolder fromPropertiesPositiveString(Properties properties) {
String pp = properties.getPositivePrefix();
String ps = properties.getPositiveSuffix();
if (pp == null && ps == null) return null;
return getInstance(pp, ps, true, false);
}
- static AffixHolder fromPropertiesNegativeString(IProperties properties) {
+ static AffixHolder fromPropertiesNegativeString(Properties properties) {
String np = properties.getNegativePrefix();
String ns = properties.getNegativeSuffix();
if (np == null && ns == null) return null;
0xFE63, 0xFE63, 0xFF0D, 0xFF0D)
.freeze();
- public static Number parse(String input, IProperties properties, DecimalFormatSymbols symbols) {
+ public static Number parse(String input, Properties properties, DecimalFormatSymbols symbols) {
ParsePosition ppos = threadLocalParsePosition.get();
ppos.setIndex(0);
return parse(input, ppos, properties, symbols);
public static Number parse(
CharSequence input,
ParsePosition ppos,
- IProperties properties,
+ Properties properties,
DecimalFormatSymbols symbols) {
StateItem best = _parse(input, ppos, false, properties, symbols);
return (best == null) ? null : best.toNumber(properties);
}
public static CurrencyAmount parseCurrency(
- String input, IProperties properties, DecimalFormatSymbols symbols) throws ParseException {
+ String input, Properties properties, DecimalFormatSymbols symbols) throws ParseException {
return parseCurrency(input, null, properties, symbols);
}
public static CurrencyAmount parseCurrency(
- CharSequence input, ParsePosition ppos, IProperties properties, DecimalFormatSymbols symbols)
+ CharSequence input, ParsePosition ppos, Properties properties, DecimalFormatSymbols symbols)
throws ParseException {
if (ppos == null) {
ppos = threadLocalParsePosition.get();
CharSequence input,
ParsePosition ppos,
boolean parseCurrency,
- IProperties properties,
+ Properties properties,
DecimalFormatSymbols symbols) {
if (input == null || ppos == null || properties == null || symbols == null) {
// Optionally require that the presence of a decimal point matches the pattern.
if (properties.getDecimalPatternMatchRequired()
- && item.sawDecimalPoint != PositiveDecimalFormat.allowsDecimalPoint(properties)) {
+ && item.sawDecimalPoint
+ != (properties.getDecimalSeparatorAlwaysShown()
+ || properties.getMaximumFractionDigits() != 0)) {
if (DEBUGGING) System.out.println("-> rejected due to decimal point violation");
continue;
}
import java.math.BigDecimal;
-import com.ibm.icu.impl.number.formatters.PaddingFormat;
-import com.ibm.icu.impl.number.formatters.PaddingFormat.PadPosition;
+import com.ibm.icu.impl.number.ThingsNeedingNewHome.PadPosition;
import com.ibm.icu.text.DecimalFormatSymbols;
import newapi.impl.AffixPatternProvider;
// Figure out the grouping sizes.
int grouping1, grouping2, grouping;
- if (groupingSize != Math.min(dosMax, Properties.DEFAULT_SECONDARY_GROUPING_SIZE)
- && firstGroupingSize != Math.min(dosMax, Properties.DEFAULT_GROUPING_SIZE)
+ if (groupingSize != Math.min(dosMax, -1)
+ && firstGroupingSize != Math.min(dosMax, -1)
&& groupingSize != firstGroupingSize) {
grouping = groupingSize;
grouping1 = groupingSize;
grouping2 = firstGroupingSize;
- } else if (groupingSize != Math.min(dosMax, Properties.DEFAULT_SECONDARY_GROUPING_SIZE)) {
+ } else if (groupingSize != Math.min(dosMax, -1)) {
grouping = groupingSize;
grouping1 = 0;
grouping2 = groupingSize;
- } else if (firstGroupingSize != Math.min(dosMax, Properties.DEFAULT_GROUPING_SIZE)) {
+ } else if (firstGroupingSize != Math.min(dosMax, -1)) {
grouping = groupingSize;
grouping1 = 0;
grouping2 = firstGroupingSize;
BigDecimal roundingInterval = properties.getRoundingIncrement();
StringBuilder digitsString = new StringBuilder();
int digitsStringScale = 0;
- if (maxSig != Math.min(dosMax, Properties.DEFAULT_MAXIMUM_SIGNIFICANT_DIGITS)) {
+ if (maxSig != Math.min(dosMax, -1)) {
// Significant Digits.
while (digitsString.length() < minSig) {
digitsString.append('@');
while (digitsString.length() < maxSig) {
digitsString.append('#');
}
- } else if (roundingInterval != Properties.DEFAULT_ROUNDING_INCREMENT) {
+ } else if (roundingInterval != null) {
// Rounding Interval.
digitsStringScale = -roundingInterval.scale();
// TODO: Check for DoS here?
}
// Exponential notation
- if (exponentDigits != Math.min(dosMax, Properties.DEFAULT_MINIMUM_EXPONENT_DIGITS)) {
+ if (exponentDigits != Math.min(dosMax, -1)) {
sb.append('E');
if (exponentShowPlusSign) {
sb.append('+');
AffixPatternUtils.escape(ps, sb);
// Resolve Padding
- if (paddingWidth != Properties.DEFAULT_FORMAT_WIDTH) {
+ if (paddingWidth != -1) {
while (paddingWidth - sb.length() > 0) {
sb.insert(afterPrefixPos, '#');
beforeSuffixPos++;
/** @return The number of chars inserted. */
private static int escapePaddingString(CharSequence input, StringBuilder output, int startIndex) {
- if (input == null || input.length() == 0) input = PaddingFormat.FALLBACK_PADDING_STRING;
+ if (input == null || input.length() == 0) input = ThingsNeedingNewHome.FALLBACK_PADDING_STRING;
int startLength = output.length();
if (input.length() == 1) {
if (input.equals("'")) {
if (grouping2 != -1) {
properties.setGroupingSize(grouping1);
} else {
- properties.setGroupingSize(Properties.DEFAULT_GROUPING_SIZE);
+ properties.setGroupingSize(-1);
}
if (grouping3 != -1) {
properties.setSecondaryGroupingSize(grouping2);
} else {
- properties.setSecondaryGroupingSize(Properties.DEFAULT_SECONDARY_GROUPING_SIZE);
+ properties.setSecondaryGroupingSize(-1);
}
// For backwards compatibility, require that the pattern emit at least one min digit.
// Rounding settings
// Don't set basic rounding when there is a currency sign; defer to CurrencyUsage
if (positive.minimumSignificantDigits > 0) {
- properties.setMinimumFractionDigits(Properties.DEFAULT_MINIMUM_FRACTION_DIGITS);
- properties.setMaximumFractionDigits(Properties.DEFAULT_MAXIMUM_FRACTION_DIGITS);
- properties.setRoundingIncrement(Properties.DEFAULT_ROUNDING_INCREMENT);
+ properties.setMinimumFractionDigits(-1);
+ properties.setMaximumFractionDigits(-1);
+ properties.setRoundingIncrement(null);
properties.setMinimumSignificantDigits(positive.minimumSignificantDigits);
properties.setMaximumSignificantDigits(positive.maximumSignificantDigits);
} else if (positive.rounding != null) {
properties.setRoundingIncrement(
positive.rounding.toBigDecimal().setScale(positive.minimumFractionDigits));
} else {
- properties.setMinimumFractionDigits(Properties.DEFAULT_MINIMUM_FRACTION_DIGITS);
- properties.setMaximumFractionDigits(Properties.DEFAULT_MAXIMUM_FRACTION_DIGITS);
- properties.setRoundingIncrement(Properties.DEFAULT_ROUNDING_INCREMENT);
+ properties.setMinimumFractionDigits(-1);
+ properties.setMaximumFractionDigits(-1);
+ properties.setRoundingIncrement(null);
}
- properties.setMinimumSignificantDigits(Properties.DEFAULT_MINIMUM_SIGNIFICANT_DIGITS);
- properties.setMaximumSignificantDigits(Properties.DEFAULT_MAXIMUM_SIGNIFICANT_DIGITS);
+ properties.setMinimumSignificantDigits(-1);
+ properties.setMaximumSignificantDigits(-1);
} else {
if (!ignoreRounding) {
properties.setMinimumFractionDigits(minFrac);
properties.setMaximumFractionDigits(positive.maximumFractionDigits);
- properties.setRoundingIncrement(Properties.DEFAULT_ROUNDING_INCREMENT);
+ properties.setRoundingIncrement(null);
} else {
- properties.setMinimumFractionDigits(Properties.DEFAULT_MINIMUM_FRACTION_DIGITS);
- properties.setMaximumFractionDigits(Properties.DEFAULT_MAXIMUM_FRACTION_DIGITS);
- properties.setRoundingIncrement(Properties.DEFAULT_ROUNDING_INCREMENT);
+ properties.setMinimumFractionDigits(-1);
+ properties.setMaximumFractionDigits(-1);
+ properties.setRoundingIncrement(null);
}
- properties.setMinimumSignificantDigits(Properties.DEFAULT_MINIMUM_SIGNIFICANT_DIGITS);
- properties.setMaximumSignificantDigits(Properties.DEFAULT_MAXIMUM_SIGNIFICANT_DIGITS);
+ properties.setMinimumSignificantDigits(-1);
+ properties.setMaximumSignificantDigits(-1);
}
// If the pattern ends with a '.' then force the decimal point.
} else {
// patterns with '@' cannot define max integer digits
properties.setMinimumIntegerDigits(1);
- properties.setMaximumIntegerDigits(Properties.DEFAULT_MAXIMUM_INTEGER_DIGITS);
+ properties.setMaximumIntegerDigits(-1);
}
} else {
- properties.setExponentSignAlwaysShown(Properties.DEFAULT_EXPONENT_SIGN_ALWAYS_SHOWN);
- properties.setMinimumExponentDigits(Properties.DEFAULT_MINIMUM_EXPONENT_DIGITS);
+ properties.setExponentSignAlwaysShown(false);
+ properties.setMinimumExponentDigits(-1);
properties.setMinimumIntegerDigits(minInt);
- properties.setMaximumIntegerDigits(Properties.DEFAULT_MAXIMUM_INTEGER_DIGITS);
+ properties.setMaximumIntegerDigits(-1);
}
// Compute the affix patterns (required for both padding and affixes)
assert positive.paddingLocation != null;
properties.setPadPosition(positive.paddingLocation);
} else {
- properties.setFormatWidth(Properties.DEFAULT_FORMAT_WIDTH);
- properties.setPadString(Properties.DEFAULT_PAD_STRING);
- properties.setPadPosition(Properties.DEFAULT_PAD_POSITION);
+ properties.setFormatWidth(-1);
+ properties.setPadString(null);
+ properties.setPadPosition(null);
}
// Set the affixes
} else if (positive.hasPerMilleSign) {
properties.setMagnitudeMultiplier(3);
} else {
- properties.setMagnitudeMultiplier(Properties.DEFAULT_MAGNITUDE_MULTIPLIER);
+ properties.setMagnitudeMultiplier(0);
}
}
}
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
+import java.text.ParsePosition;
import java.util.ArrayList;
import java.util.Map;
import com.ibm.icu.impl.number.Parse.GroupingMode;
import com.ibm.icu.impl.number.Parse.ParseMode;
-import com.ibm.icu.impl.number.formatters.BigDecimalMultiplier;
-import com.ibm.icu.impl.number.formatters.CompactDecimalFormat;
-import com.ibm.icu.impl.number.formatters.CurrencyFormat;
-import com.ibm.icu.impl.number.formatters.CurrencyFormat.CurrencyStyle;
-import com.ibm.icu.impl.number.formatters.MagnitudeMultiplier;
-import com.ibm.icu.impl.number.formatters.MeasureFormat;
-import com.ibm.icu.impl.number.formatters.PaddingFormat;
-import com.ibm.icu.impl.number.formatters.PaddingFormat.PadPosition;
-import com.ibm.icu.impl.number.formatters.PositiveDecimalFormat;
-import com.ibm.icu.impl.number.formatters.PositiveNegativeAffixFormat;
-import com.ibm.icu.impl.number.formatters.ScientificFormat;
-import com.ibm.icu.impl.number.rounders.IncrementRounder;
-import com.ibm.icu.impl.number.rounders.MagnitudeRounder;
-import com.ibm.icu.impl.number.rounders.SignificantDigitsRounder;
+import com.ibm.icu.impl.number.ThingsNeedingNewHome.PadPosition;
import com.ibm.icu.text.CompactDecimalFormat.CompactStyle;
import com.ibm.icu.text.CurrencyPluralInfo;
-import com.ibm.icu.text.MeasureFormat.FormatWidth;
import com.ibm.icu.text.PluralRules;
import com.ibm.icu.util.Currency;
import com.ibm.icu.util.Currency.CurrencyUsage;
-import com.ibm.icu.util.MeasureUnit;
-
-public class Properties
- implements Cloneable,
- Serializable,
- PositiveDecimalFormat.IProperties,
- PositiveNegativeAffixFormat.IProperties,
- MagnitudeMultiplier.IProperties,
- ScientificFormat.IProperties,
- MeasureFormat.IProperties,
- CompactDecimalFormat.IProperties,
- PaddingFormat.IProperties,
- BigDecimalMultiplier.IProperties,
- CurrencyFormat.IProperties,
- Parse.IProperties,
- IncrementRounder.IProperties,
- MagnitudeRounder.IProperties,
- SignificantDigitsRounder.IProperties,
- Endpoint.IProperties {
+
+public class Properties implements Cloneable, Serializable {
private static final Properties DEFAULT = new Properties();
private transient CompactStyle compactStyle;
private transient Currency currency;
private transient CurrencyPluralInfo currencyPluralInfo;
- private transient CurrencyStyle currencyStyle;
private transient CurrencyUsage currencyUsage;
private transient boolean decimalPatternMatchRequired;
private transient boolean decimalSeparatorAlwaysShown;
private transient int maximumFractionDigits;
private transient int maximumIntegerDigits;
private transient int maximumSignificantDigits;
- private transient FormatWidth measureFormatWidth;
- private transient MeasureUnit measureUnit;
private transient int minimumExponentDigits;
private transient int minimumFractionDigits;
private transient int minimumGroupingDigits;
clear();
}
+ /**
+ * Sets all properties to their defaults (unset).
+ *
+ * <p>All integers default to -1 EXCEPT FOR MAGNITUDE MULTIPLIER which has a default of 0 (since
+ * negative numbers are important).
+ *
+ * <p>All booleans default to false.
+ *
+ * <p>All non-primitive types default to null.
+ *
+ * @return The property bag, for chaining.
+ */
private Properties _clear() {
- compactCustomData = DEFAULT_COMPACT_CUSTOM_DATA;
- compactStyle = DEFAULT_COMPACT_STYLE;
- currency = DEFAULT_CURRENCY;
- currencyPluralInfo = DEFAULT_CURRENCY_PLURAL_INFO;
- currencyStyle = DEFAULT_CURRENCY_STYLE;
- currencyUsage = DEFAULT_CURRENCY_USAGE;
- decimalPatternMatchRequired = DEFAULT_DECIMAL_PATTERN_MATCH_REQUIRED;
- decimalSeparatorAlwaysShown = DEFAULT_DECIMAL_SEPARATOR_ALWAYS_SHOWN;
- exponentSignAlwaysShown = DEFAULT_EXPONENT_SIGN_ALWAYS_SHOWN;
- formatWidth = DEFAULT_FORMAT_WIDTH;
- groupingSize = DEFAULT_GROUPING_SIZE;
- magnitudeMultiplier = DEFAULT_MAGNITUDE_MULTIPLIER;
- mathContext = DEFAULT_MATH_CONTEXT;
- maximumFractionDigits = DEFAULT_MAXIMUM_FRACTION_DIGITS;
- maximumIntegerDigits = DEFAULT_MAXIMUM_INTEGER_DIGITS;
- maximumSignificantDigits = DEFAULT_MAXIMUM_SIGNIFICANT_DIGITS;
- measureFormatWidth = DEFAULT_MEASURE_FORMAT_WIDTH;
- measureUnit = DEFAULT_MEASURE_UNIT;
- minimumExponentDigits = DEFAULT_MINIMUM_EXPONENT_DIGITS;
- minimumFractionDigits = DEFAULT_MINIMUM_FRACTION_DIGITS;
- minimumGroupingDigits = DEFAULT_MINIMUM_GROUPING_DIGITS;
- minimumIntegerDigits = DEFAULT_MINIMUM_INTEGER_DIGITS;
- minimumSignificantDigits = DEFAULT_MINIMUM_SIGNIFICANT_DIGITS;
- multiplier = DEFAULT_MULTIPLIER;
- negativePrefix = DEFAULT_NEGATIVE_PREFIX;
- negativePrefixPattern = DEFAULT_NEGATIVE_PREFIX_PATTERN;
- negativeSuffix = DEFAULT_NEGATIVE_SUFFIX;
- negativeSuffixPattern = DEFAULT_NEGATIVE_SUFFIX_PATTERN;
- padPosition = DEFAULT_PAD_POSITION;
- padString = DEFAULT_PAD_STRING;
- parseCaseSensitive = DEFAULT_PARSE_CASE_SENSITIVE;
- parseGroupingMode = DEFAULT_PARSE_GROUPING_MODE;
- parseIntegerOnly = DEFAULT_PARSE_INTEGER_ONLY;
- parseMode = DEFAULT_PARSE_MODE;
- parseNoExponent = DEFAULT_PARSE_NO_EXPONENT;
- parseToBigDecimal = DEFAULT_PARSE_TO_BIG_DECIMAL;
- pluralRules = DEFAULT_PLURAL_RULES;
- positivePrefix = DEFAULT_POSITIVE_PREFIX;
- positivePrefixPattern = DEFAULT_POSITIVE_PREFIX_PATTERN;
- positiveSuffix = DEFAULT_POSITIVE_SUFFIX;
- positiveSuffixPattern = DEFAULT_POSITIVE_SUFFIX_PATTERN;
- roundingIncrement = DEFAULT_ROUNDING_INCREMENT;
- roundingMode = DEFAULT_ROUNDING_MODE;
- secondaryGroupingSize = DEFAULT_SECONDARY_GROUPING_SIZE;
- signAlwaysShown = DEFAULT_SIGN_ALWAYS_SHOWN;
+ compactCustomData = null;
+ compactStyle = null;
+ currency = null;
+ currencyPluralInfo = null;
+ currencyUsage = null;
+ decimalPatternMatchRequired = false;
+ decimalSeparatorAlwaysShown = false;
+ exponentSignAlwaysShown = false;
+ formatWidth = -1;
+ groupingSize = -1;
+ magnitudeMultiplier = 0;
+ mathContext = null;
+ maximumFractionDigits = -1;
+ maximumIntegerDigits = -1;
+ maximumSignificantDigits = -1;
+ minimumExponentDigits = -1;
+ minimumFractionDigits = -1;
+ minimumGroupingDigits = -1;
+ minimumIntegerDigits = -1;
+ minimumSignificantDigits = -1;
+ multiplier = null;
+ negativePrefix = null;
+ negativePrefixPattern = null;
+ negativeSuffix = null;
+ negativeSuffixPattern = null;
+ padPosition = null;
+ padString = null;
+ parseCaseSensitive = false;
+ parseGroupingMode = null;
+ parseIntegerOnly = false;
+ parseMode = null;
+ parseNoExponent = false;
+ parseToBigDecimal = false;
+ pluralRules = null;
+ positivePrefix = null;
+ positivePrefixPattern = null;
+ positiveSuffix = null;
+ positiveSuffixPattern = null;
+ roundingIncrement = null;
+ roundingMode = null;
+ secondaryGroupingSize = -1;
+ signAlwaysShown = false;
return this;
}
compactStyle = other.compactStyle;
currency = other.currency;
currencyPluralInfo = other.currencyPluralInfo;
- currencyStyle = other.currencyStyle;
currencyUsage = other.currencyUsage;
decimalPatternMatchRequired = other.decimalPatternMatchRequired;
decimalSeparatorAlwaysShown = other.decimalSeparatorAlwaysShown;
maximumFractionDigits = other.maximumFractionDigits;
maximumIntegerDigits = other.maximumIntegerDigits;
maximumSignificantDigits = other.maximumSignificantDigits;
- measureFormatWidth = other.measureFormatWidth;
- measureUnit = other.measureUnit;
minimumExponentDigits = other.minimumExponentDigits;
minimumFractionDigits = other.minimumFractionDigits;
minimumGroupingDigits = other.minimumGroupingDigits;
eq = eq && _equalsHelper(compactStyle, other.compactStyle);
eq = eq && _equalsHelper(currency, other.currency);
eq = eq && _equalsHelper(currencyPluralInfo, other.currencyPluralInfo);
- eq = eq && _equalsHelper(currencyStyle, other.currencyStyle);
eq = eq && _equalsHelper(currencyUsage, other.currencyUsage);
eq = eq && _equalsHelper(decimalPatternMatchRequired, other.decimalPatternMatchRequired);
eq = eq && _equalsHelper(decimalSeparatorAlwaysShown, other.decimalSeparatorAlwaysShown);
eq = eq && _equalsHelper(maximumFractionDigits, other.maximumFractionDigits);
eq = eq && _equalsHelper(maximumIntegerDigits, other.maximumIntegerDigits);
eq = eq && _equalsHelper(maximumSignificantDigits, other.maximumSignificantDigits);
- eq = eq && _equalsHelper(measureFormatWidth, other.measureFormatWidth);
- eq = eq && _equalsHelper(measureUnit, other.measureUnit);
eq = eq && _equalsHelper(minimumExponentDigits, other.minimumExponentDigits);
eq = eq && _equalsHelper(minimumFractionDigits, other.minimumFractionDigits);
eq = eq && _equalsHelper(minimumGroupingDigits, other.minimumGroupingDigits);
hashCode ^= _hashCodeHelper(compactStyle);
hashCode ^= _hashCodeHelper(currency);
hashCode ^= _hashCodeHelper(currencyPluralInfo);
- hashCode ^= _hashCodeHelper(currencyStyle);
hashCode ^= _hashCodeHelper(currencyUsage);
hashCode ^= _hashCodeHelper(decimalPatternMatchRequired);
hashCode ^= _hashCodeHelper(decimalSeparatorAlwaysShown);
hashCode ^= _hashCodeHelper(maximumFractionDigits);
hashCode ^= _hashCodeHelper(maximumIntegerDigits);
hashCode ^= _hashCodeHelper(maximumSignificantDigits);
- hashCode ^= _hashCodeHelper(measureFormatWidth);
- hashCode ^= _hashCodeHelper(measureUnit);
hashCode ^= _hashCodeHelper(minimumExponentDigits);
hashCode ^= _hashCodeHelper(minimumFractionDigits);
hashCode ^= _hashCodeHelper(minimumGroupingDigits);
/// BEGIN GETTERS/SETTERS ///
- @Override
public Map<String, Map<String, String>> getCompactCustomData() {
return compactCustomData;
}
- @Override
public CompactStyle getCompactStyle() {
return compactStyle;
}
- @Override
public Currency getCurrency() {
return currency;
}
- @Override
- @Deprecated
public CurrencyPluralInfo getCurrencyPluralInfo() {
return currencyPluralInfo;
}
- @Override
- public CurrencyStyle getCurrencyStyle() {
- return currencyStyle;
- }
-
- @Override
public CurrencyUsage getCurrencyUsage() {
return currencyUsage;
}
- @Override
public boolean getDecimalPatternMatchRequired() {
return decimalPatternMatchRequired;
}
- @Override
public boolean getDecimalSeparatorAlwaysShown() {
return decimalSeparatorAlwaysShown;
}
- @Override
public boolean getExponentSignAlwaysShown() {
return exponentSignAlwaysShown;
}
- @Override
public int getFormatWidth() {
return formatWidth;
}
- @Override
public int getGroupingSize() {
return groupingSize;
}
- @Override
public int getMagnitudeMultiplier() {
return magnitudeMultiplier;
}
- @Override
public MathContext getMathContext() {
return mathContext;
}
- @Override
public int getMaximumFractionDigits() {
return maximumFractionDigits;
}
- @Override
public int getMaximumIntegerDigits() {
return maximumIntegerDigits;
}
- @Override
public int getMaximumSignificantDigits() {
return maximumSignificantDigits;
}
- @Override
- public FormatWidth getMeasureFormatWidth() {
- return measureFormatWidth;
- }
-
- @Override
- public MeasureUnit getMeasureUnit() {
- return measureUnit;
- }
-
- @Override
public int getMinimumExponentDigits() {
return minimumExponentDigits;
}
- @Override
public int getMinimumFractionDigits() {
return minimumFractionDigits;
}
- @Override
public int getMinimumGroupingDigits() {
return minimumGroupingDigits;
}
- @Override
public int getMinimumIntegerDigits() {
return minimumIntegerDigits;
}
- @Override
public int getMinimumSignificantDigits() {
return minimumSignificantDigits;
}
- @Override
public BigDecimal getMultiplier() {
return multiplier;
}
- @Override
public String getNegativePrefix() {
return negativePrefix;
}
- @Override
public String getNegativePrefixPattern() {
return negativePrefixPattern;
}
- @Override
public String getNegativeSuffix() {
return negativeSuffix;
}
- @Override
public String getNegativeSuffixPattern() {
return negativeSuffixPattern;
}
- @Override
public PadPosition getPadPosition() {
return padPosition;
}
- @Override
public String getPadString() {
return padString;
}
- @Override
public boolean getParseCaseSensitive() {
return parseCaseSensitive;
}
- @Override
public GroupingMode getParseGroupingMode() {
return parseGroupingMode;
}
- @Override
public boolean getParseIntegerOnly() {
return parseIntegerOnly;
}
- @Override
public ParseMode getParseMode() {
return parseMode;
}
- @Override
public boolean getParseNoExponent() {
return parseNoExponent;
}
- @Override
public boolean getParseToBigDecimal() {
return parseToBigDecimal;
}
- @Override
public PluralRules getPluralRules() {
return pluralRules;
}
- @Override
public String getPositivePrefix() {
return positivePrefix;
}
- @Override
public String getPositivePrefixPattern() {
return positivePrefixPattern;
}
- @Override
public String getPositiveSuffix() {
return positiveSuffix;
}
- @Override
public String getPositiveSuffixPattern() {
return positiveSuffixPattern;
}
- @Override
public BigDecimal getRoundingIncrement() {
return roundingIncrement;
}
- @Override
public RoundingMode getRoundingMode() {
return roundingMode;
}
- @Override
public int getSecondaryGroupingSize() {
return secondaryGroupingSize;
}
- @Override
public boolean getSignAlwaysShown() {
return signAlwaysShown;
}
}
}
- @Override
+ /**
+ * Specifies custom data to be used instead of CLDR data when constructing a CompactDecimalFormat.
+ * The argument should be a map with the following structure:
+ *
+ * <pre>
+ * {
+ * "1000": {
+ * "one": "0 thousand",
+ * "other": "0 thousand"
+ * },
+ * "10000": {
+ * "one": "00 thousand",
+ * "other": "00 thousand"
+ * },
+ * // ...
+ * }
+ * </pre>
+ *
+ * This API endpoint is used by the CLDR Survey Tool.
+ *
+ * @param compactCustomData A map with the above structure.
+ * @return The property bag, for chaining.
+ */
public Properties setCompactCustomData(Map<String, Map<String, String>> compactCustomData) {
// TODO: compactCustomData is not immutable.
this.compactCustomData = compactCustomData;
return this;
}
- @Override
+ /**
+ * Use compact decimal formatting with the specified {@link CompactStyle}. CompactStyle.SHORT
+ * produces output like "10K" in locale <em>en-US</em>, whereas CompactStyle.LONG produces output
+ * like "10 thousand" in that locale.
+ *
+ * @param compactStyle The style of prefixes/suffixes to append.
+ * @return The property bag, for chaining.
+ */
public Properties setCompactStyle(CompactStyle compactStyle) {
this.compactStyle = compactStyle;
return this;
}
- @Override
+ /**
+ * Use the specified currency to substitute currency placeholders ('¤') in the pattern string.
+ *
+ * @param currency The currency.
+ * @return The property bag, for chaining.
+ */
public Properties setCurrency(Currency currency) {
this.currency = currency;
return this;
}
- @Override
- @Deprecated
+ /**
+ * Use the specified {@link CurrencyPluralInfo} instance when formatting currency long names.
+ *
+ * @param currencyPluralInfo The currency plural info object.
+ * @return The property bag, for chaining.
+ */
public Properties setCurrencyPluralInfo(CurrencyPluralInfo currencyPluralInfo) {
// TODO: In order to maintain immutability, we have to perform a clone here.
// It would be better to just retire CurrencyPluralInfo entirely.
return this;
}
- @Override
- public Properties setCurrencyStyle(CurrencyStyle currencyStyle) {
- this.currencyStyle = currencyStyle;
- return this;
- }
-
- @Override
+ /**
+ * Use the specified {@link CurrencyUsage} instance, which provides default rounding rules for the
+ * currency in two styles, CurrencyUsage.CASH and CurrencyUsage.STANDARD.
+ *
+ * <p>The CurrencyUsage specified here will not be used unless there is a currency placeholder in
+ * the pattern.
+ *
+ * @param currencyUsage The currency usage. Defaults to CurrencyUsage.STANDARD.
+ * @return The property bag, for chaining.
+ */
public Properties setCurrencyUsage(CurrencyUsage currencyUsage) {
this.currencyUsage = currencyUsage;
return this;
}
- @Override
+ /**
+ * PARSING: Whether to require that the presence of decimal point matches the pattern. If a
+ * decimal point is not present, but the pattern contained a decimal point, parse will not
+ * succeed: null will be returned from <code>parse()</code>, and an error index will be set in the
+ * {@link ParsePosition}.
+ *
+ * @param decimalPatternMatchRequired true to set an error if decimal is not present
+ * @return The property bag, for chaining.
+ */
public Properties setDecimalPatternMatchRequired(boolean decimalPatternMatchRequired) {
this.decimalPatternMatchRequired = decimalPatternMatchRequired;
return this;
}
- @Override
+ /**
+ * Sets whether to always show the decimal point, even if the number doesn't require one. For
+ * example, if always show decimal is true, the number 123 would be formatted as "123." in locale
+ * <em>en-US</em>.
+ *
+ * @param decimalSeparatorAlwaysShown Whether to show the decimal point when it is optional.
+ * @return The property bag, for chaining.
+ */
public Properties setDecimalSeparatorAlwaysShown(boolean alwaysShowDecimal) {
this.decimalSeparatorAlwaysShown = alwaysShowDecimal;
return this;
}
- @Override
+ /**
+ * Sets whether to show the plus sign in the exponent part of numbers with a zero or positive
+ * exponent. For example, the number "1200" with the pattern "0.0E0" would be formatted as
+ * "1.2E+3" instead of "1.2E3" in <em>en-US</em>.
+ *
+ * @param exponentSignAlwaysShown Whether to show the plus sign in positive exponents.
+ * @return The property bag, for chaining.
+ */
public Properties setExponentSignAlwaysShown(boolean exponentSignAlwaysShown) {
this.exponentSignAlwaysShown = exponentSignAlwaysShown;
return this;
}
- @Override
+ /**
+ * Sets the minimum width of the string output by the formatting pipeline. For example, if padding
+ * is enabled and paddingWidth is set to 6, formatting the number "3.14159" with the pattern
+ * "0.00" will result in "··3.14" if '·' is your padding string.
+ *
+ * <p>If the number is longer than your padding width, the number will display as if no padding
+ * width had been specified, which may result in strings longer than the padding width.
+ *
+ * <p>Width is counted in UTF-16 code units.
+ *
+ * @param formatWidth The output width.
+ * @return The property bag, for chaining.
+ * @see #setPadPosition
+ * @see #setPadString
+ */
public Properties setFormatWidth(int paddingWidth) {
this.formatWidth = paddingWidth;
return this;
}
- @Override
+ /**
+ * Sets the number of digits between grouping separators. For example, the <em>en-US</em> locale
+ * uses a grouping size of 3, so the number 1234567 would be formatted as "1,234,567". For locales
+ * whose grouping sizes vary with magnitude, see {@link #setSecondaryGroupingSize(int)}.
+ *
+ * @param groupingSize The primary grouping size.
+ * @return The property bag, for chaining.
+ */
public Properties setGroupingSize(int groupingSize) {
this.groupingSize = groupingSize;
return this;
}
- @Override
+ /**
+ * Multiply all numbers by this power of ten before formatting. Negative multipliers reduce the
+ * magnitude and make numbers smaller (closer to zero).
+ *
+ * @param magnitudeMultiplier The number of powers of ten to scale.
+ * @return The property bag, for chaining.
+ * @see #setMultiplier
+ */
public Properties setMagnitudeMultiplier(int magnitudeMultiplier) {
this.magnitudeMultiplier = magnitudeMultiplier;
return this;
}
- @Override
+ /**
+ * Sets the {@link MathContext} to be used during math and rounding operations. A MathContext
+ * encapsulates a RoundingMode and the number of significant digits in the output.
+ *
+ * @param mathContext The math context to use when rounding is required.
+ * @return The property bag, for chaining.
+ * @see MathContext
+ * @see #setRoundingMode
+ */
public Properties setMathContext(MathContext mathContext) {
this.mathContext = mathContext;
return this;
}
- @Override
+ /**
+ * Sets the maximum number of digits to display after the decimal point. If the number has fewer
+ * than this number of digits, the number will be rounded off using the rounding mode specified by
+ * {@link #setRoundingMode(RoundingMode)}. The pattern "#00.0#", for example, corresponds to 2
+ * maximum fraction digits, and the number 456.789 would be formatted as "456.79" in locale
+ * <em>en-US</em> with the default rounding mode. Note that the number 456.999 would be formatted
+ * as "457.0" given the same configurations.
+ *
+ * @param maximumFractionDigits The maximum number of fraction digits to output.
+ * @return The property bag, for chaining.
+ */
public Properties setMaximumFractionDigits(int maximumFractionDigits) {
this.maximumFractionDigits = maximumFractionDigits;
return this;
}
- @Override
+ /**
+ * Sets the maximum number of digits to display before the decimal point. If the number has more
+ * than this number of digits, the extra digits will be truncated. For example, if maximum integer
+ * digits is 2, and you attempt to format the number 1970, you will get "70" in locale
+ * <em>en-US</em>. It is not possible to specify the maximum integer digits using a pattern
+ * string, except in the special case of a scientific format pattern.
+ *
+ * @param maximumIntegerDigits The maximum number of integer digits to output.
+ * @return The property bag, for chaining.
+ */
public Properties setMaximumIntegerDigits(int maximumIntegerDigits) {
this.maximumIntegerDigits = maximumIntegerDigits;
return this;
}
- @Override
+ /**
+ * Sets the maximum number of significant digits to display. The number of significant digits is
+ * equal to the number of digits counted from the leftmost nonzero digit through the rightmost
+ * nonzero digit; for example, the number "2010" has 3 significant digits. If the number has more
+ * significant digits than specified here, the extra significant digits will be rounded off using
+ * the rounding mode specified by {@link #setRoundingMode(RoundingMode)}. For example, if maximum
+ * significant digits is 3, the number 1234.56 will be formatted as "1230" in locale
+ * <em>en-US</em> with the default rounding mode.
+ *
+ * <p>If both maximum significant digits and maximum integer/fraction digits are set at the same
+ * time, the behavior is undefined.
+ *
+ * <p>The number of significant digits can be specified in a pattern string using the '@'
+ * character. For example, the pattern "@@#" corresponds to a minimum of 2 and a maximum of 3
+ * significant digits.
+ *
+ * @param maximumSignificantDigits The maximum number of significant digits to display.
+ * @return The property bag, for chaining.
+ */
public Properties setMaximumSignificantDigits(int maximumSignificantDigits) {
this.maximumSignificantDigits = maximumSignificantDigits;
return this;
}
- @Override
- public Properties setMeasureFormatWidth(FormatWidth measureFormatWidth) {
- this.measureFormatWidth = measureFormatWidth;
- return this;
- }
-
- @Override
- public Properties setMeasureUnit(MeasureUnit measureUnit) {
- this.measureUnit = measureUnit;
- return this;
- }
-
- @Override
+ /**
+ * Sets the minimum number of digits to display in the exponent. For example, the number "1200"
+ * with the pattern "0.0E00", which has 2 exponent digits, would be formatted as "1.2E03" in
+ * <em>en-US</em>.
+ *
+ * @param minimumExponentDigits The minimum number of digits to display in the exponent field.
+ * @return The property bag, for chaining.
+ */
public Properties setMinimumExponentDigits(int exponentDigits) {
this.minimumExponentDigits = exponentDigits;
return this;
}
- @Override
+ /**
+ * Sets the minimum number of digits to display after the decimal point. If the number has fewer
+ * than this number of digits, the number will be padded with zeros. The pattern "#00.0#", for
+ * example, corresponds to 1 minimum fraction digit, and the number 456 would be formatted as
+ * "456.0" in locale <em>en-US</em>.
+ *
+ * @param minimumFractionDigits The minimum number of fraction digits to output.
+ * @return The property bag, for chaining.
+ */
public Properties setMinimumFractionDigits(int minimumFractionDigits) {
this.minimumFractionDigits = minimumFractionDigits;
return this;
}
- @Override
+ /**
+ * Sets the minimum number of digits required to be beyond the first grouping separator in order
+ * to enable grouping. For example, if the minimum grouping digits is 2, then 1234 would be
+ * formatted as "1234" but 12345 would be formatted as "12,345" in <em>en-US</em>. Note that
+ * 1234567 would still be formatted as "1,234,567", not "1234,567".
+ *
+ * @param minimumGroupingDigits How many digits must appear before a grouping separator before
+ * enabling grouping.
+ * @return The property bag, for chaining.
+ */
public Properties setMinimumGroupingDigits(int minimumGroupingDigits) {
this.minimumGroupingDigits = minimumGroupingDigits;
return this;
}
- @Override
+ /**
+ * Sets the minimum number of digits to display before the decimal point. If the number has fewer
+ * than this number of digits, the number will be padded with zeros. The pattern "#00.0#", for
+ * example, corresponds to 2 minimum integer digits, and the number 5.3 would be formatted as
+ * "05.3" in locale <em>en-US</em>.
+ *
+ * @param minimumIntegerDigits The minimum number of integer digits to output.
+ * @return The property bag, for chaining.
+ */
public Properties setMinimumIntegerDigits(int minimumIntegerDigits) {
this.minimumIntegerDigits = minimumIntegerDigits;
return this;
}
- @Override
+ /**
+ * Sets the minimum number of significant digits to display. If, after rounding to the number of
+ * significant digits specified by {@link #setMaximumSignificantDigits}, the number of remaining
+ * significant digits is less than the minimum, the number will be padded with zeros. For example,
+ * if minimum significant digits is 3, the number 5.8 will be formatted as "5.80" in locale
+ * <em>en-US</em>. Note that minimum significant digits is relevant only when numbers have digits
+ * after the decimal point.
+ *
+ * <p>If both minimum significant digits and minimum integer/fraction digits are set at the same
+ * time, both values will be respected, and the one that results in the greater number of padding
+ * zeros will be used. For example, formatting the number 73 with 3 minimum significant digits and
+ * 2 minimum fraction digits will produce "73.00".
+ *
+ * <p>The number of significant digits can be specified in a pattern string using the '@'
+ * character. For example, the pattern "@@#" corresponds to a minimum of 2 and a maximum of 3
+ * significant digits.
+ *
+ * @param minimumSignificantDigits The minimum number of significant digits to display.
+ * @return The property bag, for chaining.
+ */
public Properties setMinimumSignificantDigits(int minimumSignificantDigits) {
this.minimumSignificantDigits = minimumSignificantDigits;
return this;
}
- @Override
+ /**
+ * Multiply all numbers by this amount before formatting.
+ *
+ * @param multiplier The amount to multiply by.
+ * @return The property bag, for chaining.
+ * @see #setMagnitudeMultiplier
+ */
public Properties setMultiplier(BigDecimal multiplier) {
this.multiplier = multiplier;
return this;
}
- @Override
+ /**
+ * Sets the prefix to prepend to negative numbers. The prefix will be interpreted literally. For
+ * example, if you set a negative prefix of <code>n</code>, then the number -123 will be formatted
+ * as "n123" in the locale <em>en-US</em>. Note that if the negative prefix is left unset, the
+ * locale's minus sign is used.
+ *
+ * <p>For more information on prefixes and suffixes, see {@link PositiveNegativeAffixFormat}.
+ *
+ * @param negativePrefix The CharSequence to prepend to negative numbers.
+ * @return The property bag, for chaining.
+ * @see PositiveNegativeAffixFormat
+ * @see #setNegativePrefixPattern
+ */
public Properties setNegativePrefix(String negativePrefix) {
this.negativePrefix = negativePrefix;
return this;
}
- @Override
+ /**
+ * Sets the prefix to prepend to negative numbers. Locale-specific symbols will be substituted
+ * into the string according to Unicode Technical Standard #35 (LDML).
+ *
+ * <p>For more information on prefixes and suffixes, see {@link PositiveNegativeAffixFormat}.
+ *
+ * @param negativePrefixPattern The CharSequence to prepend to negative numbers after locale
+ * symbol substitutions take place.
+ * @return The property bag, for chaining.
+ * @see PositiveNegativeAffixFormat
+ * @see #setNegativePrefix
+ */
public Properties setNegativePrefixPattern(String negativePrefixPattern) {
this.negativePrefixPattern = negativePrefixPattern;
return this;
}
- @Override
+ /**
+ * Sets the suffix to append to negative numbers. The suffix will be interpreted literally. For
+ * example, if you set a suffix prefix of <code>n</code>, then the number -123 will be formatted
+ * as "-123n" in the locale <em>en-US</em>. Note that the minus sign is prepended by default
+ * unless otherwise specified in either the pattern string or in one of the {@link
+ * #setNegativePrefix} methods.
+ *
+ * <p>For more information on prefixes and suffixes, see {@link PositiveNegativeAffixFormat}.
+ *
+ * @param negativeSuffix The CharSequence to append to negative numbers.
+ * @return The property bag, for chaining.
+ * @see PositiveNegativeAffixFormat
+ * @see #setNegativeSuffixPattern
+ */
public Properties setNegativeSuffix(String negativeSuffix) {
this.negativeSuffix = negativeSuffix;
return this;
}
- @Override
+ /**
+ * Sets the suffix to append to negative numbers. Locale-specific symbols will be substituted into
+ * the string according to Unicode Technical Standard #35 (LDML).
+ *
+ * <p>For more information on prefixes and suffixes, see {@link PositiveNegativeAffixFormat}.
+ *
+ * @param negativeSuffixPattern The CharSequence to append to negative numbers after locale symbol
+ * substitutions take place.
+ * @return The property bag, for chaining.
+ * @see PositiveNegativeAffixFormat
+ * @see #setNegativeSuffix
+ */
public Properties setNegativeSuffixPattern(String negativeSuffixPattern) {
this.negativeSuffixPattern = negativeSuffixPattern;
return this;
}
- @Override
+ /**
+ * Sets the location where the padding string is to be inserted to maintain the padding width: one
+ * of BEFORE_PREFIX, AFTER_PREFIX, BEFORE_SUFFIX, or AFTER_SUFFIX.
+ *
+ * <p>Must be used in conjunction with {@link #setFormatWidth}.
+ *
+ * @param padPosition The output width.
+ * @return The property bag, for chaining.
+ * @see #setFormatWidth
+ */
public Properties setPadPosition(PadPosition paddingLocation) {
this.padPosition = paddingLocation;
return this;
}
- @Override
+ /**
+ * Sets the string used for padding. The string should contain a single character or grapheme
+ * cluster.
+ *
+ * <p>Must be used in conjunction with {@link #setFormatWidth}.
+ *
+ * @param paddingString The padding string. Defaults to an ASCII space (U+0020).
+ * @return The property bag, for chaining.
+ * @see #setFormatWidth
+ */
public Properties setPadString(String paddingString) {
this.padString = paddingString;
return this;
}
- @Override
+ /**
+ * Whether to require cases to match when parsing strings; default is true. Case sensitivity
+ * applies to prefixes, suffixes, the exponent separator, the symbol "NaN", and the infinity
+ * symbol. Grouping separators, decimal separators, and padding are always case-sensitive.
+ * Currencies are always case-insensitive.
+ *
+ * <p>This setting is ignored in fast mode. In fast mode, strings are always compared in a
+ * case-sensitive way.
+ *
+ * @param parseCaseSensitive true to be case-sensitive when parsing; false to allow any case.
+ * @return The property bag, for chaining.
+ */
public Properties setParseCaseSensitive(boolean parseCaseSensitive) {
this.parseCaseSensitive = parseCaseSensitive;
return this;
}
- @Override
+ /**
+ * Sets the strategy used during parsing when a code point needs to be interpreted as either a
+ * decimal separator or a grouping separator.
+ *
+ * <p>The comma, period, space, and apostrophe have different meanings in different locales. For
+ * example, in <em>en-US</em> and most American locales, the period is used as a decimal
+ * separator, but in <em>es-PY</em> and most European locales, it is used as a grouping separator.
+ *
+ * <p>Suppose you are in <em>fr-FR</em> the parser encounters the string "1.234". In
+ * <em>fr-FR</em>, the grouping is a space and the decimal is a comma. The <em>grouping mode</em>
+ * is a mechanism to let you specify whether to accept the string as 1234 (GroupingMode.DEFAULT)
+ * or whether to reject it since the separators don't match (GroupingMode.RESTRICTED).
+ *
+ * <p>When resolving grouping separators, it is the <em>equivalence class</em> of separators that
+ * is considered. For example, a period is seen as equal to a fixed set of other period-like
+ * characters.
+ *
+ * @param parseGroupingMode The {@link GroupingMode} to use; either DEFAULT or RESTRICTED.
+ * @return The property bag, for chaining.
+ */
public Properties setParseGroupingMode(GroupingMode parseGroupingMode) {
this.parseGroupingMode = parseGroupingMode;
return this;
}
- @Override
+ /**
+ * Whether to ignore the fractional part of numbers. For example, parses "123.4" to "123" instead
+ * of "123.4".
+ *
+ * @param parseIntegerOnly true to parse integers only; false to parse integers with their
+ * fraction parts
+ * @return The property bag, for chaining.
+ */
public Properties setParseIntegerOnly(boolean parseIntegerOnly) {
this.parseIntegerOnly = parseIntegerOnly;
return this;
}
- @Override
+ /**
+ * Controls certain rules for how strict this parser is when reading strings. See {@link
+ * ParseMode#LENIENT} and {@link ParseMode#STRICT}.
+ *
+ * @param parseMode Either {@link ParseMode#LENIENT} or {@link ParseMode#STRICT}.
+ * @return The property bag, for chaining.
+ */
public Properties setParseMode(ParseMode parseMode) {
this.parseMode = parseMode;
return this;
}
- @Override
+ /**
+ * Whether to ignore the exponential part of numbers. For example, parses "123E4" to "123" instead
+ * of "1230000".
+ *
+ * @param parseIgnoreExponent true to ignore exponents; false to parse them.
+ * @return The property bag, for chaining.
+ */
public Properties setParseNoExponent(boolean parseNoExponent) {
this.parseNoExponent = parseNoExponent;
return this;
}
- @Override
+ /**
+ * Whether to always return a BigDecimal from {@link Parse#parse} and all other parse methods. By
+ * default, a Long or a BigInteger are returned when possible.
+ *
+ * @param parseToBigDecimal true to always return a BigDecimal; false to return a Long or a
+ * BigInteger when possible.
+ * @return The property bag, for chaining.
+ */
public Properties setParseToBigDecimal(boolean parseToBigDecimal) {
this.parseToBigDecimal = parseToBigDecimal;
return this;
}
- @Override
+ /**
+ * Sets the PluralRules object to use instead of the default for the locale.
+ *
+ * @param pluralRules The object to reference.
+ * @return The property bag, for chaining.
+ */
public Properties setPluralRules(PluralRules pluralRules) {
this.pluralRules = pluralRules;
return this;
}
- @Override
+ /**
+ * Sets the prefix to prepend to positive numbers. The prefix will be interpreted literally. For
+ * example, if you set a positive prefix of <code>p</code>, then the number 123 will be formatted
+ * as "p123" in the locale <em>en-US</em>.
+ *
+ * <p>For more information on prefixes and suffixes, see {@link PositiveNegativeAffixFormat}.
+ *
+ * @param positivePrefix The CharSequence to prepend to positive numbers.
+ * @return The property bag, for chaining.
+ * @see PositiveNegativeAffixFormat
+ * @see #setPositivePrefixPattern
+ */
public Properties setPositivePrefix(String positivePrefix) {
this.positivePrefix = positivePrefix;
return this;
}
- @Override
+ /**
+ * Sets the prefix to prepend to positive numbers. Locale-specific symbols will be substituted
+ * into the string according to Unicode Technical Standard #35 (LDML).
+ *
+ * <p>For more information on prefixes and suffixes, see {@link PositiveNegativeAffixFormat}.
+ *
+ * @param positivePrefixPattern The CharSequence to prepend to positive numbers after locale
+ * symbol substitutions take place.
+ * @return The property bag, for chaining.
+ * @see PositiveNegativeAffixFormat
+ * @see #setPositivePrefix
+ */
public Properties setPositivePrefixPattern(String positivePrefixPattern) {
this.positivePrefixPattern = positivePrefixPattern;
return this;
}
- @Override
+ /**
+ * Sets the suffix to append to positive numbers. The suffix will be interpreted literally. For
+ * example, if you set a positive suffix of <code>p</code>, then the number 123 will be formatted
+ * as "123p" in the locale <em>en-US</em>.
+ *
+ * <p>For more information on prefixes and suffixes, see {@link PositiveNegativeAffixFormat}.
+ *
+ * @param positiveSuffix The CharSequence to append to positive numbers.
+ * @return The property bag, for chaining.
+ * @see PositiveNegativeAffixFormat
+ * @see #setPositiveSuffixPattern
+ */
public Properties setPositiveSuffix(String positiveSuffix) {
this.positiveSuffix = positiveSuffix;
return this;
}
- @Override
+ /**
+ * Sets the suffix to append to positive numbers. Locale-specific symbols will be substituted into
+ * the string according to Unicode Technical Standard #35 (LDML).
+ *
+ * <p>For more information on prefixes and suffixes, see {@link PositiveNegativeAffixFormat}.
+ *
+ * @param positiveSuffixPattern The CharSequence to append to positive numbers after locale symbol
+ * substitutions take place.
+ * @return The property bag, for chaining.
+ * @see PositiveNegativeAffixFormat
+ * @see #setPositiveSuffix
+ */
public Properties setPositiveSuffixPattern(String positiveSuffixPattern) {
this.positiveSuffixPattern = positiveSuffixPattern;
return this;
}
- @Override
+ /**
+ * Sets the increment to which to round numbers. For example, with a rounding interval of 0.05,
+ * the number 11.17 would be formatted as "11.15" in locale <em>en-US</em> with the default
+ * rounding mode.
+ *
+ * <p>You can use either a rounding increment or significant digits, but not both at the same
+ * time.
+ *
+ * <p>The rounding increment can be specified in a pattern string. For example, the pattern
+ * "#,##0.05" corresponds to a rounding interval of 0.05 with 1 minimum integer digit and a
+ * grouping size of 3.
+ *
+ * @param roundingIncrement The interval to which to round.
+ * @return The property bag, for chaining.
+ */
public Properties setRoundingIncrement(BigDecimal roundingIncrement) {
this.roundingIncrement = roundingIncrement;
return this;
}
- @Override
+ /**
+ * Sets the rounding mode, which determines under which conditions extra decimal places are
+ * rounded either up or down. See {@link RoundingMode} for details on the choices of rounding
+ * mode. The default if not set explicitly is {@link RoundingMode#HALF_EVEN}.
+ *
+ * <p>This setting is ignored if {@link #setMathContext} is used.
+ *
+ * @param roundingMode The rounding mode to use when rounding is required.
+ * @return The property bag, for chaining.
+ * @see RoundingMode
+ * @see #setMathContext
+ */
public Properties setRoundingMode(RoundingMode roundingMode) {
this.roundingMode = roundingMode;
return this;
}
- @Override
+ /**
+ * Sets the number of digits between grouping separators higher than the least-significant
+ * grouping separator. For example, the locale <em>hi</em> uses a primary grouping size of 3 and a
+ * secondary grouping size of 2, so the number 1234567 would be formatted as "12,34,567".
+ *
+ * <p>The two levels of grouping separators can be specified in the pattern string. For example,
+ * the <em>hi</em> locale's default decimal format pattern is "#,##,##0.###".
+ *
+ * @param secondaryGroupingSize The secondary grouping size.
+ * @return The property bag, for chaining.
+ */
public Properties setSecondaryGroupingSize(int secondaryGroupingSize) {
this.secondaryGroupingSize = secondaryGroupingSize;
return this;
}
- @Override
+ /**
+ * Sets whether to always display of a plus sign on positive numbers.
+ *
+ * <p>If the location of the negative sign is specified by the decimal format pattern (or by the
+ * negative prefix/suffix pattern methods), a plus sign is substituted into that location, in
+ * accordance with Unicode Technical Standard #35 (LDML) section 3.2.1. Otherwise, the plus sign
+ * is prepended to the number. For example, if the decimal format pattern <code>#;#-</code> is
+ * used, then formatting 123 would result in "123+" in the locale <em>en-US</em>.
+ *
+ * <p>This method should be used <em>instead of</em> setting the positive prefix/suffix. The
+ * behavior is undefined if alwaysShowPlusSign is set but the positive prefix/suffix already
+ * contains a plus sign.
+ *
+ * @param plusSignAlwaysShown Whether positive numbers should display a plus sign.
+ * @return The property bag, for chaining.
+ */
public Properties setSignAlwaysShown(boolean signAlwaysShown) {
this.signAlwaysShown = signAlwaysShown;
return this;
+++ /dev/null
-// © 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 java.math.MathContext;
-import java.math.RoundingMode;
-
-import com.ibm.icu.impl.number.formatters.CompactDecimalFormat;
-import com.ibm.icu.impl.number.formatters.ScientificFormat;
-
-/**
- * The base class for a Rounder used by ICU Decimal Format.
- *
- * <p>A Rounder must implement the method {@link #apply}. An implementation must:
- *
- * <ol>
- * <li>Either have the code <code>applyDefaults(input);</code> in its apply function, or otherwise
- * ensure that minFrac, maxFrac, minInt, and maxInt are obeyed, paying special attention to
- * the case when the input is zero.
- * <li>Call one of {@link FormatQuantity#roundToIncrement}, {@link
- * FormatQuantity#roundToMagnitude}, or {@link FormatQuantity#roundToInfinity} on the input.
- * </ol>
- *
- * <p>In order to be used by {@link CompactDecimalFormat} and {@link ScientificFormat}, among
- * others, your rounder must be stable upon <em>decreasing</em> the magnitude of the input number.
- * For example, if your rounder converts "999" to "1000", it must also convert "99.9" to "100" and
- * "0.999" to "1". (The opposite does not need to be the case: you can round "0.999" to "1" but keep
- * "999" as "999".)
- *
- * @see com.ibm.icu.impl.number.rounders.MagnitudeRounder
- * @see com.ibm.icu.impl.number.rounders.IncrementRounder
- * @see com.ibm.icu.impl.number.rounders.SignificantDigitsRounder
- * @see com.ibm.icu.impl.number.rounders.NoRounder
- */
-public abstract class Rounder extends Format.BeforeFormat {
-
- public static interface IBasicRoundingProperties {
-
- static int DEFAULT_MINIMUM_INTEGER_DIGITS = -1;
-
- /** @see #setMinimumIntegerDigits */
- public int getMinimumIntegerDigits();
-
- /**
- * Sets the minimum number of digits to display before the decimal point. If the number has
- * fewer than this number of digits, the number will be padded with zeros. The pattern "#00.0#",
- * for example, corresponds to 2 minimum integer digits, and the number 5.3 would be formatted
- * as "05.3" in locale <em>en-US</em>.
- *
- * @param minimumIntegerDigits The minimum number of integer digits to output.
- * @return The property bag, for chaining.
- */
- public IBasicRoundingProperties setMinimumIntegerDigits(int minimumIntegerDigits);
-
- static int DEFAULT_MAXIMUM_INTEGER_DIGITS = -1;
-
- /** @see #setMaximumIntegerDigits */
- public int getMaximumIntegerDigits();
-
- /**
- * Sets the maximum number of digits to display before the decimal point. If the number has more
- * than this number of digits, the extra digits will be truncated. For example, if maximum
- * integer digits is 2, and you attempt to format the number 1970, you will get "70" in locale
- * <em>en-US</em>. It is not possible to specify the maximum integer digits using a pattern
- * string, except in the special case of a scientific format pattern.
- *
- * @param maximumIntegerDigits The maximum number of integer digits to output.
- * @return The property bag, for chaining.
- */
- public IBasicRoundingProperties setMaximumIntegerDigits(int maximumIntegerDigits);
-
- static int DEFAULT_MINIMUM_FRACTION_DIGITS = -1;
-
- /** @see #setMinimumFractionDigits */
- public int getMinimumFractionDigits();
-
- /**
- * Sets the minimum number of digits to display after the decimal point. If the number has fewer
- * than this number of digits, the number will be padded with zeros. The pattern "#00.0#", for
- * example, corresponds to 1 minimum fraction digit, and the number 456 would be formatted as
- * "456.0" in locale <em>en-US</em>.
- *
- * @param minimumFractionDigits The minimum number of fraction digits to output.
- * @return The property bag, for chaining.
- */
- public IBasicRoundingProperties setMinimumFractionDigits(int minimumFractionDigits);
-
- static int DEFAULT_MAXIMUM_FRACTION_DIGITS = -1;
-
- /** @see #setMaximumFractionDigits */
- public int getMaximumFractionDigits();
-
- /**
- * Sets the maximum number of digits to display after the decimal point. If the number has fewer
- * than this number of digits, the number will be rounded off using the rounding mode specified
- * by {@link #setRoundingMode(RoundingMode)}. The pattern "#00.0#", for example, corresponds to
- * 2 maximum fraction digits, and the number 456.789 would be formatted as "456.79" in locale
- * <em>en-US</em> with the default rounding mode. Note that the number 456.999 would be
- * formatted as "457.0" given the same configurations.
- *
- * @param maximumFractionDigits The maximum number of fraction digits to output.
- * @return The property bag, for chaining.
- */
- public IBasicRoundingProperties setMaximumFractionDigits(int maximumFractionDigits);
-
- static RoundingMode DEFAULT_ROUNDING_MODE = null;
-
- /** @see #setRoundingMode */
- public RoundingMode getRoundingMode();
-
- /**
- * Sets the rounding mode, which determines under which conditions extra decimal places are
- * rounded either up or down. See {@link RoundingMode} for details on the choices of rounding
- * mode. The default if not set explicitly is {@link RoundingMode#HALF_EVEN}.
- *
- * <p>This setting is ignored if {@link #setMathContext} is used.
- *
- * @param roundingMode The rounding mode to use when rounding is required.
- * @return The property bag, for chaining.
- * @see RoundingMode
- * @see #setMathContext
- */
- public IBasicRoundingProperties setRoundingMode(RoundingMode roundingMode);
-
- static MathContext DEFAULT_MATH_CONTEXT = null;
-
- /** @see #setMathContext */
- public MathContext getMathContext();
-
- /**
- * Sets the {@link MathContext} to be used during math and rounding operations. A MathContext
- * encapsulates a RoundingMode and the number of significant digits in the output.
- *
- * @param mathContext The math context to use when rounding is required.
- * @return The property bag, for chaining.
- * @see MathContext
- * @see #setRoundingMode
- */
- public IBasicRoundingProperties setMathContext(MathContext mathContext);
- }
-
- public static interface MultiplierGenerator {
- public int getMultiplier(int magnitude);
- }
-
- // Properties available to all rounding strategies
- protected final MathContext mathContext;
- protected final int minInt;
- protected final int maxInt;
- protected final int minFrac;
- protected final int maxFrac;
-
- /**
- * Constructor that uses integer and fraction digit lengths from IBasicRoundingProperties.
- *
- * @param properties
- */
- protected Rounder(IBasicRoundingProperties properties) {
- mathContext = RoundingUtils.getMathContextOrUnlimited(properties);
-
- int _maxInt = properties.getMaximumIntegerDigits();
- int _minInt = properties.getMinimumIntegerDigits();
- int _maxFrac = properties.getMaximumFractionDigits();
- int _minFrac = properties.getMinimumFractionDigits();
-
- // Validate min/max int/frac.
- // For backwards compatibility, minimum overrides maximum if the two conflict.
- // The following logic ensures that there is always a minimum of at least one digit.
- if (_minInt == 0 && _maxFrac != 0) {
- // Force a digit after the decimal point.
- minFrac = _minFrac <= 0 ? 1 : _minFrac;
- maxFrac = _maxFrac < 0 ? Integer.MAX_VALUE : _maxFrac < minFrac ? minFrac : _maxFrac;
- minInt = 0;
- maxInt = _maxInt < 0 ? Integer.MAX_VALUE : _maxInt;
- } else {
- // Force a digit before the decimal point.
- minFrac = _minFrac < 0 ? 0 : _minFrac;
- maxFrac = _maxFrac < 0 ? Integer.MAX_VALUE : _maxFrac < minFrac ? minFrac : _maxFrac;
- minInt = _minInt <= 0 ? 1 : _minInt;
- maxInt = _maxInt < 0 ? Integer.MAX_VALUE : _maxInt < minInt ? minInt : _maxInt;
- }
- }
-
- /**
- * Perform rounding and specification of integer and fraction digit lengths on the input quantity.
- * Calling this method will change the state of the FormatQuantity.
- *
- * @param input The {@link FormatQuantity} to be modified and rounded.
- */
- public abstract void apply(FormatQuantity input);
-
- /**
- * Rounding can affect the magnitude. First we attempt to adjust according to the original
- * magnitude, and if the magnitude changes, we adjust according to a magnitude one greater. Note
- * that this algorithm assumes that increasing the multiplier never increases the number of digits
- * that can be displayed.
- *
- * @param input The quantity to be rounded.
- * @param mg The implementation that returns magnitude adjustment based on a given starting
- * magnitude.
- * @return The multiplier that was chosen to best fit the input.
- */
- public int chooseMultiplierAndApply(FormatQuantity input, MultiplierGenerator mg) {
- // TODO: Avoid the object creation here.
- FormatQuantity copy = input.createCopy();
-
- assert !input.isZero();
- int magnitude = input.getMagnitude();
- int multiplier = mg.getMultiplier(magnitude);
- input.adjustMagnitude(multiplier);
- apply(input);
-
- // If the number turned to zero when rounding, do not re-attempt the rounding.
- if (!input.isZero() && input.getMagnitude() == magnitude + multiplier + 1) {
- magnitude += 1;
- input.copyFrom(copy);
- multiplier = mg.getMultiplier(magnitude);
- input.adjustMagnitude(multiplier);
- assert input.getMagnitude() == magnitude + multiplier - 1;
- apply(input);
- assert input.getMagnitude() == magnitude + multiplier;
- }
-
- return multiplier;
- }
-
- /**
- * Implementations can call this method to perform default logic for min/max digits. This method
- * performs logic for handling of a zero input.
- *
- * @param input The digits being formatted.
- */
- protected void applyDefaults(FormatQuantity input) {
- input.setIntegerLength(minInt, maxInt);
- input.setFractionLength(minFrac, maxFrac);
- }
-
- @Override
- public void before(FormatQuantity input, ModifierHolder mods) {
- apply(input);
- }
-
- @Override
- public void export(Properties properties) {
- properties.setMathContext(mathContext);
- properties.setRoundingMode(mathContext.getRoundingMode());
- properties.setMinimumFractionDigits(minFrac);
- properties.setMinimumIntegerDigits(minInt);
- properties.setMaximumFractionDigits(maxFrac);
- properties.setMaximumIntegerDigits(maxInt);
- }
-}
import java.math.MathContext;
import java.math.RoundingMode;
-import com.ibm.icu.impl.number.Rounder.IBasicRoundingProperties;
-
/** @author sffc */
public class RoundingUtils {
* @param properties The property bag.
* @return A {@link MathContext}. Never null.
*/
- public static MathContext getMathContextOrUnlimited(IBasicRoundingProperties properties) {
+ public static MathContext getMathContextOrUnlimited(Properties properties) {
MathContext mathContext = properties.getMathContext();
if (mathContext == null) {
RoundingMode roundingMode = properties.getRoundingMode();
* @param properties The property bag.
* @return A {@link MathContext}. Never null.
*/
- public static MathContext getMathContextOr34Digits(IBasicRoundingProperties properties) {
+ public static MathContext getMathContextOr34Digits(Properties properties) {
MathContext mathContext = properties.getMathContext();
if (mathContext == null) {
RoundingMode roundingMode = properties.getRoundingMode();
--- /dev/null
+// © 2017 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html#License
+package com.ibm.icu.impl.number;
+
+/** @author sffc */
+public class ThingsNeedingNewHome {
+ public static final String FALLBACK_PADDING_STRING = "\u0020"; // i.e. a space
+
+ public enum PadPosition {
+ BEFORE_PREFIX,
+ AFTER_PREFIX,
+ BEFORE_SUFFIX,
+ AFTER_SUFFIX;
+
+ public static PadPosition fromOld(int old) {
+ switch (old) {
+ case com.ibm.icu.text.DecimalFormat.PAD_BEFORE_PREFIX:
+ return PadPosition.BEFORE_PREFIX;
+ case com.ibm.icu.text.DecimalFormat.PAD_AFTER_PREFIX:
+ return PadPosition.AFTER_PREFIX;
+ case com.ibm.icu.text.DecimalFormat.PAD_BEFORE_SUFFIX:
+ return PadPosition.BEFORE_SUFFIX;
+ case com.ibm.icu.text.DecimalFormat.PAD_AFTER_SUFFIX:
+ return PadPosition.AFTER_SUFFIX;
+ default:
+ throw new IllegalArgumentException("Don't know how to map " + old);
+ }
+ }
+
+ public int toOld() {
+ switch (this) {
+ case BEFORE_PREFIX:
+ return com.ibm.icu.text.DecimalFormat.PAD_BEFORE_PREFIX;
+ case AFTER_PREFIX:
+ return com.ibm.icu.text.DecimalFormat.PAD_AFTER_PREFIX;
+ case BEFORE_SUFFIX:
+ return com.ibm.icu.text.DecimalFormat.PAD_BEFORE_SUFFIX;
+ case AFTER_SUFFIX:
+ return com.ibm.icu.text.DecimalFormat.PAD_AFTER_SUFFIX;
+ default:
+ return -1; // silence compiler errors
+ }
+ }
+ }
+
+ /**
+ * Returns true if the currency is set in The property bag or if currency symbols are present in
+ * the prefix/suffix pattern.
+ */
+ public static boolean useCurrency(Properties properties) {
+ return ((properties.getCurrency() != null)
+ || properties.getCurrencyPluralInfo() != null
+ || properties.getCurrencyUsage() != null
+ || AffixPatternUtils.hasCurrencySymbols(properties.getPositivePrefixPattern())
+ || AffixPatternUtils.hasCurrencySymbols(properties.getPositiveSuffixPattern())
+ || AffixPatternUtils.hasCurrencySymbols(properties.getNegativePrefixPattern())
+ || AffixPatternUtils.hasCurrencySymbols(properties.getNegativeSuffixPattern()));
+ }
+}
+++ /dev/null
-// © 2017 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html#License
-package com.ibm.icu.impl.number.formatters;
-
-import java.math.BigDecimal;
-
-import com.ibm.icu.impl.number.Format.BeforeFormat;
-import com.ibm.icu.impl.number.FormatQuantity;
-import com.ibm.icu.impl.number.ModifierHolder;
-import com.ibm.icu.impl.number.Properties;
-
-public class BigDecimalMultiplier extends BeforeFormat {
- public static interface IProperties {
-
- static BigDecimal DEFAULT_MULTIPLIER = null;
-
- /** @see #setMultiplier */
- public BigDecimal getMultiplier();
-
- /**
- * Multiply all numbers by this amount before formatting.
- *
- * @param multiplier The amount to multiply by.
- * @return The property bag, for chaining.
- * @see MagnitudeMultiplier
- */
- public IProperties setMultiplier(BigDecimal multiplier);
- }
-
- public static boolean useMultiplier(IProperties properties) {
- return properties.getMultiplier() != IProperties.DEFAULT_MULTIPLIER;
- }
-
- private final BigDecimal multiplier;
-
- public static BigDecimalMultiplier getInstance(IProperties properties) {
- if (properties.getMultiplier() == null) {
- throw new IllegalArgumentException("The multiplier must be present for MultiplierFormat");
- }
- // TODO: Intelligently fall back to a MagnitudeMultiplier if the multiplier is a power of ten?
- return new BigDecimalMultiplier(properties);
- }
-
- private BigDecimalMultiplier(IProperties properties) {
- this.multiplier = properties.getMultiplier();
- }
-
- @Override
- public void before(FormatQuantity input, ModifierHolder mods) {
- input.multiplyBy(multiplier);
- }
-
- @Override
- public void export(Properties properties) {
- properties.setMultiplier(multiplier);
- }
-}
+++ /dev/null
-// © 2017 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html#License
-package com.ibm.icu.impl.number.formatters;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.MissingResourceException;
-
-import com.ibm.icu.impl.ICUData;
-import com.ibm.icu.impl.ICUResourceBundle;
-import com.ibm.icu.impl.StandardPlural;
-import com.ibm.icu.impl.UResource;
-import com.ibm.icu.impl.number.Format;
-import com.ibm.icu.impl.number.FormatQuantity;
-import com.ibm.icu.impl.number.Modifier;
-import com.ibm.icu.impl.number.Modifier.PositiveNegativeModifier;
-import com.ibm.icu.impl.number.ModifierHolder;
-import com.ibm.icu.impl.number.PNAffixGenerator;
-import com.ibm.icu.impl.number.PatternString;
-import com.ibm.icu.impl.number.Properties;
-import com.ibm.icu.impl.number.Rounder;
-import com.ibm.icu.impl.number.modifiers.ConstantAffixModifier;
-import com.ibm.icu.impl.number.modifiers.PositiveNegativeAffixModifier;
-import com.ibm.icu.impl.number.rounders.SignificantDigitsRounder;
-import com.ibm.icu.text.CompactDecimalFormat.CompactStyle;
-import com.ibm.icu.text.CompactDecimalFormat.CompactType;
-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.ULocale;
-import com.ibm.icu.util.UResourceBundle;
-
-public class CompactDecimalFormat extends Format.BeforeFormat {
- public static interface IProperties
- extends RoundingFormat.IProperties, CurrencyFormat.ICurrencyProperties {
-
- static CompactStyle DEFAULT_COMPACT_STYLE = null;
-
- /** @see #setCompactStyle */
- public CompactStyle getCompactStyle();
-
- /**
- * Use compact decimal formatting with the specified {@link CompactStyle}. CompactStyle.SHORT
- * produces output like "10K" in locale <em>en-US</em>, whereas CompactStyle.LONG produces
- * output like "10 thousand" in that locale.
- *
- * @param compactStyle The style of prefixes/suffixes to append.
- * @return The property bag, for chaining.
- */
- public IProperties setCompactStyle(CompactStyle compactStyle);
-
- static Map<String, Map<String, String>> DEFAULT_COMPACT_CUSTOM_DATA = null;
-
- /** @see #setCompactCustomData */
- public Map<String, Map<String, String>> getCompactCustomData();
-
- /**
- * Specifies custom data to be used instead of CLDR data when constructing a
- * CompactDecimalFormat. The argument should be a map with the following structure:
- *
- * <pre>
- * {
- * "1000": {
- * "one": "0 thousand",
- * "other": "0 thousand"
- * },
- * "10000": {
- * "one": "00 thousand",
- * "other": "00 thousand"
- * },
- * // ...
- * }
- * </pre>
- *
- * This API endpoint is used by the CLDR Survey Tool.
- *
- * @param compactCustomData A map with the above structure.
- * @return The property bag, for chaining.
- * @internal
- * @deprecated This API is ICU internal only.
- */
- @Deprecated
- public IProperties setCompactCustomData(Map<String, Map<String, String>> compactCustomData);
- }
-
- public static boolean useCompactDecimalFormat(IProperties properties) {
- return properties.getCompactStyle() != IProperties.DEFAULT_COMPACT_STYLE;
- }
-
- static final int MAX_DIGITS = 15;
-
- // Properties
- private final CompactDecimalData data;
- private final Rounder rounder;
- private final PositiveNegativeModifier defaultMod;
- private final CompactStyle style; // retained for exporting only
-
- public static CompactDecimalFormat getInstance(
- DecimalFormatSymbols symbols, IProperties properties) {
- return new CompactDecimalFormat(symbols, properties);
- }
-
- private static final int DEFAULT_MIN_SIG = 1;
- private static final int DEFAULT_MAX_SIG = 2;
-
- private static final ThreadLocal<Properties> threadLocalProperties =
- new ThreadLocal<Properties>() {
- @Override
- protected Properties initialValue() {
- return new Properties();
- }
- };
-
- private static Rounder getRounder(IProperties properties) {
- // Use rounding settings if they were specified, or else use the default CDF rounder.
- // TODO: Detecting and overriding significant digits here is a bit of a hack, since detection
- // is also performed in the "RoundingFormat.getDefaultOrNull" method.
- // It would be more elegant to call some sort of "fallback" copy method.
- Rounder rounder = null;
- if (!SignificantDigitsRounder.useSignificantDigits(properties)) {
- rounder = RoundingFormat.getDefaultOrNull(properties);
- }
- if (rounder == null) {
- int _minSig = properties.getMinimumSignificantDigits();
- int _maxSig = properties.getMaximumSignificantDigits();
- Properties rprops = threadLocalProperties.get().clear();
- // Settings needing possible override:
- rprops.setMinimumSignificantDigits(_minSig > 0 ? _minSig : DEFAULT_MIN_SIG);
- rprops.setMaximumSignificantDigits(_maxSig > 0 ? _maxSig : DEFAULT_MAX_SIG);
- // TODO: Should copyFrom() be used instead? It requires a cast.
- // Settings to copy verbatim:
- rprops.setRoundingMode(properties.getRoundingMode());
- rprops.setMinimumFractionDigits(properties.getMinimumFractionDigits());
- rprops.setMaximumFractionDigits(properties.getMaximumFractionDigits());
- rprops.setMinimumIntegerDigits(properties.getMinimumIntegerDigits());
- rprops.setMaximumIntegerDigits(properties.getMaximumIntegerDigits());
- rounder = SignificantDigitsRounder.getInstance(rprops);
- }
- return rounder;
- }
-
- protected static final ThreadLocal<Map<CompactDecimalFingerprint, CompactDecimalData>>
- threadLocalDataCache =
- new ThreadLocal<Map<CompactDecimalFingerprint, CompactDecimalData>>() {
- @Override
- protected Map<CompactDecimalFingerprint, CompactDecimalData> initialValue() {
- return new HashMap<CompactDecimalFingerprint, CompactDecimalData>();
- }
- };
-
- private static CompactDecimalData getData(
- DecimalFormatSymbols symbols, CompactDecimalFingerprint fingerprint) {
- // See if we already have a data object based on the fingerprint
- CompactDecimalData data = threadLocalDataCache.get().get(fingerprint);
- if (data != null) return data;
-
- // Make data bundle object
- data = new CompactDecimalData();
- ULocale ulocale = symbols.getULocale();
- CompactDecimalDataSink sink = new CompactDecimalDataSink(data, symbols, fingerprint);
- String nsName = NumberingSystem.getInstance(ulocale).getName();
- ICUResourceBundle rb =
- (ICUResourceBundle) UResourceBundle.getBundleInstance(ICUData.ICU_BASE_NAME, ulocale);
- internalPopulateData(nsName, rb, sink, data);
- if (data.isEmpty() && fingerprint.compactStyle == CompactStyle.LONG) {
- // No long data is available; load short data instead
- sink.compactStyle = CompactStyle.SHORT;
- internalPopulateData(nsName, rb, sink, data);
- }
- threadLocalDataCache.get().put(fingerprint, data);
- return data;
- }
-
- private static void internalPopulateData(
- String nsName, ICUResourceBundle rb, CompactDecimalDataSink sink, CompactDecimalData data) {
- try {
- rb.getAllItemsWithFallback("NumberElements/" + nsName, sink);
- } catch (MissingResourceException e) {
- // Fall back to latn
- }
- if (data.isEmpty() && !nsName.equals("latn")) {
- rb.getAllItemsWithFallback("NumberElements/latn", sink);
- }
- if (sink.exception != null) {
- throw sink.exception;
- }
- }
-
- private static PositiveNegativeModifier getDefaultMod(
- DecimalFormatSymbols symbols, CompactDecimalFingerprint fingerprint) {
- ULocale uloc = symbols.getULocale();
- String pattern;
- if (fingerprint.compactType == CompactType.CURRENCY) {
- pattern = NumberFormat.getPatternForStyle(uloc, NumberFormat.CURRENCYSTYLE);
- } else {
- pattern = NumberFormat.getPatternForStyle(uloc, NumberFormat.NUMBERSTYLE);
- }
- // TODO: Clean this up; avoid the extra object creations.
- // TODO: Currency may also need to override grouping settings, not just affixes.
- Properties properties = PatternString.parseToProperties(pattern);
- PNAffixGenerator pnag = PNAffixGenerator.getThreadLocalInstance();
- PNAffixGenerator.Result result =
- pnag.getModifiers(symbols, fingerprint.currencySymbol, properties);
- return new PositiveNegativeAffixModifier(result.positive, result.negative);
- }
-
- private CompactDecimalFormat(DecimalFormatSymbols symbols, IProperties properties) {
- CompactDecimalFingerprint fingerprint = new CompactDecimalFingerprint(symbols, properties);
- this.rounder = getRounder(properties);
- // Short-circuit and use custom data if provided
- if (properties.getCompactCustomData() != null) {
- this.data = createDataFromCustom(symbols, fingerprint, properties.getCompactCustomData());
- } else {
- this.data = getData(symbols, fingerprint);
- }
- this.defaultMod = getDefaultMod(symbols, fingerprint);
- this.style = properties.getCompactStyle(); // for exporting only
- }
-
- @Override
- public void before(FormatQuantity input, ModifierHolder mods, PluralRules rules) {
- apply(input, mods, rules, rounder, data, defaultMod);
- }
-
- @Override
- protected void before(FormatQuantity input, ModifierHolder mods) {
- throw new UnsupportedOperationException();
- }
-
- public static void apply(
- FormatQuantity input,
- ModifierHolder mods,
- PluralRules rules,
- DecimalFormatSymbols symbols,
- IProperties properties) {
- CompactDecimalFingerprint fingerprint = new CompactDecimalFingerprint(symbols, properties);
- Rounder rounder = getRounder(properties);
- CompactDecimalData data = getData(symbols, fingerprint);
- PositiveNegativeModifier defaultMod = getDefaultMod(symbols, fingerprint);
- apply(input, mods, rules, rounder, data, defaultMod);
- }
-
- private static void apply(
- FormatQuantity input,
- ModifierHolder mods,
- PluralRules rules,
- Rounder rounder,
- CompactDecimalData data,
- PositiveNegativeModifier defaultMod) {
-
- // Treat zero as if it had magnitude 0
- int magnitude;
- if (input.isZero()) {
- magnitude = 0;
- rounder.apply(input);
- } else {
- // TODO: Revisit chooseMultiplierAndApply
- int multiplier = rounder.chooseMultiplierAndApply(input, data);
- magnitude = input.isZero() ? 0 : input.getMagnitude();
- magnitude -= multiplier;
- }
-
- StandardPlural plural = input.getStandardPlural(rules);
- boolean isNegative = input.isNegative();
- Modifier mod = data.getModifier(magnitude, plural, isNegative);
- if (mod == null) {
- // Use the default (non-compact) modifier.
- mod = defaultMod.getModifier(isNegative);
- }
- mods.add(mod);
- }
-
- @Override
- public void export(Properties properties) {
- properties.setCompactStyle(style);
- rounder.export(properties);
- }
-
- static class CompactDecimalData implements Rounder.MultiplierGenerator {
-
- // A dummy object used when a "0" compact decimal entry is encountered. This is necessary
- // in order to prevent falling back to root.
- private static final Modifier USE_FALLBACK = new ConstantAffixModifier();
-
- final Modifier[] mods;
- final byte[] multipliers;
- boolean isEmpty;
- int largestMagnitude;
-
- CompactDecimalData() {
- mods = new Modifier[(MAX_DIGITS + 1) * StandardPlural.COUNT * 2];
- multipliers = new byte[MAX_DIGITS + 1];
- isEmpty = true;
- largestMagnitude = -1;
- }
-
- boolean isEmpty() {
- return isEmpty;
- }
-
- @Override
- public int getMultiplier(int magnitude) {
- if (magnitude < 0) {
- return 0;
- }
- if (magnitude > largestMagnitude) {
- magnitude = largestMagnitude;
- }
- return multipliers[magnitude];
- }
-
- int setOrGetMultiplier(int magnitude, byte multiplier) {
- if (multipliers[magnitude] != 0) {
- return multipliers[magnitude];
- }
- multipliers[magnitude] = multiplier;
- isEmpty = false;
- if (magnitude > largestMagnitude) largestMagnitude = magnitude;
- return multiplier;
- }
-
- Modifier getModifier(int magnitude, StandardPlural plural, boolean isNegative) {
- if (magnitude < 0) {
- return null;
- }
- if (magnitude > largestMagnitude) {
- magnitude = largestMagnitude;
- }
- Modifier mod = mods[modIndex(magnitude, plural, isNegative)];
- if (mod == null && plural != StandardPlural.OTHER) {
- // Fall back to "other" plural variant
- mod = mods[modIndex(magnitude, StandardPlural.OTHER, isNegative)];
- }
- if (mod == USE_FALLBACK) {
- // Return null if USE_FALLBACK is present
- mod = null;
- }
- return mod;
- }
-
- public boolean has(int magnitude, StandardPlural plural) {
- // Return true if USE_FALLBACK is present
- return mods[modIndex(magnitude, plural, false)] != null;
- }
-
- void setModifiers(Modifier positive, Modifier negative, int magnitude, StandardPlural plural) {
- mods[modIndex(magnitude, plural, false)] = positive;
- mods[modIndex(magnitude, plural, true)] = negative;
- isEmpty = false;
- if (magnitude > largestMagnitude) largestMagnitude = magnitude;
- }
-
- void setNoFallback(int magnitude, StandardPlural plural) {
- setModifiers(USE_FALLBACK, USE_FALLBACK, magnitude, plural);
- }
-
- private static final int modIndex(int magnitude, StandardPlural plural, boolean isNegative) {
- return magnitude * StandardPlural.COUNT * 2 + plural.ordinal() * 2 + (isNegative ? 1 : 0);
- }
- }
-
- static class CompactDecimalFingerprint {
- // TODO: Add more stuff to the fingerprint, like the symbols used by PNAffixGenerator
- final CompactStyle compactStyle;
- final CompactType compactType;
- final ULocale uloc;
- final String currencySymbol;
-
- CompactDecimalFingerprint(DecimalFormatSymbols symbols, IProperties properties) {
- // CompactDecimalFormat does not need to worry about the same constraints as non-compact
- // currency formatting needs to consider, like the currency rounding mode and the currency
- // long names with plural forms.
- if (properties.getCurrency() != CurrencyFormat.ICurrencyProperties.DEFAULT_CURRENCY) {
- compactType = CompactType.CURRENCY;
- currencySymbol = CurrencyFormat.getCurrencySymbol(symbols, properties);
- } else {
- compactType = CompactType.DECIMAL;
- currencySymbol = ""; // fallback; should remain unused
- }
- compactStyle = properties.getCompactStyle();
- uloc = symbols.getULocale();
- }
-
- @Override
- public boolean equals(Object _other) {
- if (_other == null) return false;
- CompactDecimalFingerprint other = (CompactDecimalFingerprint) _other;
- if (this == other) return true;
- if (compactStyle != other.compactStyle) return false;
- if (compactType != other.compactType) return false;
- if (currencySymbol != other.currencySymbol) {
- // String comparison with null handling
- if (currencySymbol == null || other.currencySymbol == null) return false;
- if (!currencySymbol.equals(other.currencySymbol)) return false;
- }
- if (!uloc.equals(other.uloc)) return false;
- return true;
- }
-
- @Override
- public int hashCode() {
- int hashCode = 0;
- if (compactStyle != null) hashCode ^= compactStyle.hashCode();
- if (compactType != null) hashCode ^= compactType.hashCode();
- if (uloc != null) hashCode ^= uloc.hashCode();
- if (currencySymbol != null) hashCode ^= currencySymbol.hashCode();
- return hashCode;
- }
- }
-
- private static final class CompactDecimalDataSink extends UResource.Sink {
-
- CompactDecimalData data;
- DecimalFormatSymbols symbols;
- CompactStyle compactStyle;
- CompactType compactType;
- String currencySymbol;
- PNAffixGenerator pnag;
- IllegalArgumentException exception;
-
- /*
- * NumberElements{ <-- top (numbering system table)
- * latn{ <-- patternsTable (one per numbering system)
- * patternsLong{ <-- formatsTable (one per pattern)
- * decimalFormat{ <-- powersOfTenTable (one per format)
- * 1000{ <-- pluralVariantsTable (one per power of ten)
- * one{"0 thousand"} <-- plural variant and template
- */
-
- public CompactDecimalDataSink(
- CompactDecimalData data,
- DecimalFormatSymbols symbols,
- CompactDecimalFingerprint fingerprint) {
- this.data = data;
- this.symbols = symbols;
- compactType = fingerprint.compactType;
- currencySymbol = fingerprint.currencySymbol;
- compactStyle = fingerprint.compactStyle;
- pnag = PNAffixGenerator.getThreadLocalInstance();
- }
-
- @Override
- public void put(UResource.Key key, UResource.Value value, boolean isRoot) {
- UResource.Table patternsTable = value.getTable();
- for (int i1 = 0; patternsTable.getKeyAndValue(i1, key, value); ++i1) {
- if (key.contentEquals("patternsShort") && compactStyle == CompactStyle.SHORT) {
- } else if (key.contentEquals("patternsLong") && compactStyle == CompactStyle.LONG) {
- } else {
- continue;
- }
-
- // traverse into the table of formats
- UResource.Table formatsTable = value.getTable();
- for (int i2 = 0; formatsTable.getKeyAndValue(i2, key, value); ++i2) {
- if (key.contentEquals("decimalFormat") && compactType == CompactType.DECIMAL) {
- } else if (key.contentEquals("currencyFormat") && compactType == CompactType.CURRENCY) {
- } else {
- continue;
- }
-
- // traverse into the table of powers of ten
- UResource.Table powersOfTenTable = value.getTable();
- for (int i3 = 0; powersOfTenTable.getKeyAndValue(i3, key, value); ++i3) {
- try {
-
- // Assumes that the keys are always of the form "10000" where the magnitude is the
- // length of the key minus one
- byte magnitude = (byte) (key.length() - 1);
-
- // Silently ignore divisors that are too big.
- if (magnitude >= MAX_DIGITS) continue;
-
- // Iterate over the plural variants ("one", "other", etc)
- UResource.Table pluralVariantsTable = value.getTable();
- for (int i4 = 0; pluralVariantsTable.getKeyAndValue(i4, key, value); ++i4) {
-
- // Skip this magnitude/plural if we already have it from a child locale.
- StandardPlural plural = StandardPlural.fromString(key.toString());
- if (data.has(magnitude, plural)) {
- continue;
- }
-
- // The value "0" means that we need to use the default pattern and not fall back
- // to parent locales. Example locale where this is relevant: 'it'.
- String patternString = value.toString();
- if (patternString.equals("0")) {
- data.setNoFallback(magnitude, plural);
- continue;
- }
-
- // The magnitude multiplier is the difference between the magnitude and the number
- // of zeros in the pattern, getMinimumIntegerDigits.
- Properties properties = PatternString.parseToProperties(patternString);
- byte _multiplier = (byte) -(magnitude - properties.getMinimumIntegerDigits() + 1);
- if (_multiplier != data.setOrGetMultiplier(magnitude, _multiplier)) {
- throw new IllegalArgumentException(
- String.format(
- "Different number of zeros for same power of ten in compact decimal format data for locale '%s', style '%s', type '%s'",
- symbols.getULocale().toString(),
- compactStyle.toString(),
- compactType.toString()));
- }
-
- PNAffixGenerator.Result result =
- pnag.getModifiers(symbols, currencySymbol, properties);
- data.setModifiers(result.positive, result.negative, magnitude, plural);
- }
-
- } catch (IllegalArgumentException e) {
- exception = e;
- continue;
- }
- }
-
- // We want only one table of compact decimal formats, so if we get here, stop consuming.
- // The data.isEmpty() check will prevent further bundles from being traversed.
- return;
- }
- }
- }
- }
-
- /**
- * Uses data from the custom powersToPluralsToPatterns map instead of an ICUResourceBundle to
- * populate an instance of CompactDecimalData.
- */
- static CompactDecimalData createDataFromCustom(
- DecimalFormatSymbols symbols,
- CompactDecimalFingerprint fingerprint,
- Map<String, Map<String, String>> powersToPluralsToPatterns) {
- CompactDecimalData data = new CompactDecimalData();
- PNAffixGenerator pnag = PNAffixGenerator.getThreadLocalInstance();
- for (Map.Entry<String, Map<String, String>> magnitudeEntry :
- powersToPluralsToPatterns.entrySet()) {
- byte magnitude = (byte) (magnitudeEntry.getKey().length() - 1);
- for (Map.Entry<String, String> pluralEntry : magnitudeEntry.getValue().entrySet()) {
- StandardPlural plural = StandardPlural.fromString(pluralEntry.getKey().toString());
- String patternString = pluralEntry.getValue().toString();
- Properties properties = PatternString.parseToProperties(patternString);
- byte _multiplier = (byte) -(magnitude - properties.getMinimumIntegerDigits() + 1);
- if (_multiplier != data.setOrGetMultiplier(magnitude, _multiplier)) {
- throw new IllegalArgumentException(
- "Different number of zeros for same power of ten in custom compact decimal format data");
- }
- PNAffixGenerator.Result result =
- pnag.getModifiers(symbols, fingerprint.currencySymbol, properties);
- data.setModifiers(result.positive, result.negative, magnitude, plural);
- }
- }
- return data;
- }
-}
+++ /dev/null
-// © 2017 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html#License
-package com.ibm.icu.impl.number.formatters;
-
-import java.math.BigDecimal;
-
-import com.ibm.icu.impl.StandardPlural;
-import com.ibm.icu.impl.number.AffixPatternUtils;
-import com.ibm.icu.impl.number.PNAffixGenerator;
-import com.ibm.icu.impl.number.PatternString;
-import com.ibm.icu.impl.number.Properties;
-import com.ibm.icu.impl.number.Rounder;
-import com.ibm.icu.impl.number.modifiers.GeneralPluralModifier;
-import com.ibm.icu.impl.number.rounders.IncrementRounder;
-import com.ibm.icu.impl.number.rounders.MagnitudeRounder;
-import com.ibm.icu.impl.number.rounders.SignificantDigitsRounder;
-import com.ibm.icu.text.CurrencyPluralInfo;
-import com.ibm.icu.text.DecimalFormatSymbols;
-import com.ibm.icu.util.Currency;
-import com.ibm.icu.util.Currency.CurrencyUsage;
-
-public class CurrencyFormat {
-
- public enum CurrencyStyle {
- SYMBOL,
- ISO_CODE;
- }
-
- public static interface ICurrencyProperties {
- static Currency DEFAULT_CURRENCY = null;
-
- /** @see #setCurrency */
- public Currency getCurrency();
-
- /**
- * Use the specified currency to substitute currency placeholders ('¤') in the pattern string.
- *
- * @param currency The currency.
- * @return The property bag, for chaining.
- */
- public IProperties setCurrency(Currency currency);
-
- static CurrencyStyle DEFAULT_CURRENCY_STYLE = null;
-
- /** @see #setCurrencyStyle */
- public CurrencyStyle getCurrencyStyle();
-
- /**
- * Use the specified {@link CurrencyStyle} to replace currency placeholders ('¤').
- * CurrencyStyle.SYMBOL will use the short currency symbol, like "$" or "€", whereas
- * CurrencyStyle.ISO_CODE will use the ISO 4217 currency code, like "USD" or "EUR".
- *
- * <p>For long currency names, use {@link MeasureFormat.IProperties#setMeasureUnit}.
- *
- * @param currencyStyle The currency style. Defaults to CurrencyStyle.SYMBOL.
- * @return The property bag, for chaining.
- */
- public IProperties setCurrencyStyle(CurrencyStyle currencyStyle);
-
- /**
- * An old enum that specifies how currencies should be rounded. It contains a subset of the
- * functionality supported by RoundingInterval.
- */
- static Currency.CurrencyUsage DEFAULT_CURRENCY_USAGE = null;
-
- /** @see #setCurrencyUsage */
- public Currency.CurrencyUsage getCurrencyUsage();
-
- /**
- * Use the specified {@link CurrencyUsage} instance, which provides default rounding rules for
- * the currency in two styles, CurrencyUsage.CASH and CurrencyUsage.STANDARD.
- *
- * <p>The CurrencyUsage specified here will not be used unless there is a currency placeholder
- * in the pattern.
- *
- * @param currencyUsage The currency usage. Defaults to CurrencyUsage.STANDARD.
- * @return The property bag, for chaining.
- */
- public IProperties setCurrencyUsage(Currency.CurrencyUsage currencyUsage);
-
- static CurrencyPluralInfo DEFAULT_CURRENCY_PLURAL_INFO = null;
-
- /** @see #setCurrencyPluralInfo */
- @Deprecated
- public CurrencyPluralInfo getCurrencyPluralInfo();
-
- /**
- * Use the specified {@link CurrencyPluralInfo} instance when formatting currency long names.
- *
- * @param currencyPluralInfo The currency plural info object.
- * @return The property bag, for chaining.
- * @deprecated Use {@link MeasureFormat.IProperties#setMeasureUnit} with a Currency instead.
- */
- @Deprecated
- public IProperties setCurrencyPluralInfo(CurrencyPluralInfo currencyPluralInfo);
- }
-
- public static interface IProperties
- extends ICurrencyProperties,
- RoundingFormat.IProperties,
- PositiveNegativeAffixFormat.IProperties {}
-
- /**
- * Returns true if the currency is set in The property bag or if currency symbols are present in
- * the prefix/suffix pattern.
- */
- public static boolean useCurrency(IProperties properties) {
- return ((properties.getCurrency() != null)
- || properties.getCurrencyPluralInfo() != null
- || properties.getCurrencyUsage() != null
- || AffixPatternUtils.hasCurrencySymbols(properties.getPositivePrefixPattern())
- || AffixPatternUtils.hasCurrencySymbols(properties.getPositiveSuffixPattern())
- || AffixPatternUtils.hasCurrencySymbols(properties.getNegativePrefixPattern())
- || AffixPatternUtils.hasCurrencySymbols(properties.getNegativeSuffixPattern()));
- }
-
- /**
- * Returns the effective currency symbol based on the input. If {@link
- * ICurrencyProperties#setCurrencyStyle} was set to {@link CurrencyStyle#ISO_CODE}, the ISO Code
- * will be returned; otherwise, the currency symbol, like "$", will be returned.
- *
- * @param symbols The current {@link DecimalFormatSymbols} instance
- * @param properties The current property bag
- * @return The currency symbol string, e.g., to substitute '¤' in a decimal pattern string.
- */
- public static String getCurrencySymbol(
- DecimalFormatSymbols symbols, ICurrencyProperties properties) {
- // If the user asked for ISO Code, return the ISO Code instead of the symbol
- CurrencyStyle style = properties.getCurrencyStyle();
- if (style == CurrencyStyle.ISO_CODE) {
- return getCurrencyIsoCode(symbols, properties);
- }
-
- // Get the currency symbol
- Currency currency = properties.getCurrency();
- if (currency == null) {
- return symbols.getCurrencySymbol();
- } else if (currency.equals(symbols.getCurrency())) {
- // The user may have set a custom currency symbol in DecimalFormatSymbols.
- return symbols.getCurrencySymbol();
- } else {
- // Use the canonical symbol.
- return currency.getName(symbols.getULocale(), Currency.SYMBOL_NAME, null);
- }
- }
-
- /**
- * Returns the currency ISO code based on the input, like "USD".
- *
- * @param symbols The current {@link DecimalFormatSymbols} instance
- * @param properties The current property bag
- * @return The currency ISO code string, e.g., to substitute '¤¤' in a decimal pattern string.
- */
- public static String getCurrencyIsoCode(
- DecimalFormatSymbols symbols, ICurrencyProperties properties) {
- Currency currency = properties.getCurrency();
- if (currency == null) {
- // If a currency object was not provided, use the string from symbols
- // Note: symbols.getCurrency().getCurrencyCode() won't work here because
- // DecimalFormatSymbols#setInternationalCurrencySymbol() does not update the
- // immutable internal currency instance.
- return symbols.getInternationalCurrencySymbol();
- } else if (currency.equals(symbols.getCurrency())) {
- // The user may have set a custom currency symbol in DecimalFormatSymbols.
- return symbols.getInternationalCurrencySymbol();
- } else {
- // Use the canonical currency code.
- return currency.getCurrencyCode();
- }
- }
-
- /**
- * Returns the currency long name on the input, like "US dollars".
- *
- * @param symbols The current {@link DecimalFormatSymbols} instance
- * @param properties The current property bag
- * @param plural The plural form
- * @return The currency long name string, e.g., to substitute '¤¤¤' in a decimal pattern string.
- */
- public static String getCurrencyLongName(
- DecimalFormatSymbols symbols, ICurrencyProperties properties, StandardPlural plural) {
- // Attempt to get a currency object first from properties then from symbols
- Currency currency = properties.getCurrency();
- if (currency == null) {
- currency = symbols.getCurrency();
- }
-
- // If no currency object is available, fall back to the currency symbol
- if (currency == null) {
- return getCurrencySymbol(symbols, properties);
- }
-
- // Get the long name
- return currency.getName(
- symbols.getULocale(), Currency.PLURAL_LONG_NAME, plural.getKeyword(), null);
- }
-
- public static GeneralPluralModifier getCurrencyModifier(
- DecimalFormatSymbols symbols, IProperties properties) {
-
- PNAffixGenerator pnag = PNAffixGenerator.getThreadLocalInstance();
- String sym = getCurrencySymbol(symbols, properties);
- String iso = getCurrencyIsoCode(symbols, properties);
-
- // Previously, the user was also able to specify '¤¤' and '¤¤¤' directly into the prefix or
- // suffix, which is how the user specified whether they wanted the ISO code or long name.
- // For backwards compatibility support, that feature is implemented here.
-
- CurrencyPluralInfo info = properties.getCurrencyPluralInfo();
- GeneralPluralModifier mod = new GeneralPluralModifier();
- Properties temp = new Properties();
- for (StandardPlural plural : StandardPlural.VALUES) {
- String longName = getCurrencyLongName(symbols, properties, plural);
-
- PNAffixGenerator.Result result;
- if (info == null) {
- // CurrencyPluralInfo is not available.
- result = pnag.getModifiers(symbols, sym, iso, longName, properties);
- } else {
- // CurrencyPluralInfo is available. Use it to generate affixes for long name support.
- String pluralPattern = info.getCurrencyPluralPattern(plural.getKeyword());
- PatternString.parseToExistingProperties(
- pluralPattern, temp, PatternString.IGNORE_ROUNDING_ALWAYS);
- result = pnag.getModifiers(symbols, sym, iso, longName, temp);
- }
- mod.put(plural, result.positive, result.negative);
- }
- return mod;
- }
-
- private static final Currency DEFAULT_CURRENCY = Currency.getInstance("XXX");
-
- public static void populateCurrencyRounderProperties(
- Properties destination, DecimalFormatSymbols symbols, IProperties properties) {
-
- Currency currency = properties.getCurrency();
- if (currency == null) {
- // Fall back to the DecimalFormatSymbols currency instance.
- currency = symbols.getCurrency();
- }
- if (currency == null) {
- // There is a currency symbol in the pattern, but we have no currency available to use.
- // Use the default currency instead so that we can still apply currency usage rules.
- currency = DEFAULT_CURRENCY;
- }
-
- CurrencyUsage _currencyUsage = properties.getCurrencyUsage();
- int _minFrac = properties.getMinimumFractionDigits();
- int _maxFrac = properties.getMaximumFractionDigits();
-
- CurrencyUsage effectiveCurrencyUsage =
- (_currencyUsage != null) ? _currencyUsage : CurrencyUsage.STANDARD;
- double incrementDouble = currency.getRoundingIncrement(effectiveCurrencyUsage);
- int fractionDigits = currency.getDefaultFractionDigits(effectiveCurrencyUsage);
-
- destination.setRoundingMode(properties.getRoundingMode());
- destination.setMinimumIntegerDigits(properties.getMinimumIntegerDigits());
- destination.setMaximumIntegerDigits(properties.getMaximumIntegerDigits());
-
- if (_currencyUsage == null && (_minFrac >= 0 || _maxFrac >= 0)) {
- // User override of fraction length
- if (_minFrac < 0) {
- destination.setMinimumFractionDigits(fractionDigits < _maxFrac ? fractionDigits : _maxFrac);
- destination.setMaximumFractionDigits(_maxFrac);
- } else if (_maxFrac < 0) {
- destination.setMinimumFractionDigits(_minFrac);
- destination.setMaximumFractionDigits(fractionDigits > _minFrac ? fractionDigits : _minFrac);
- } else {
- destination.setMinimumFractionDigits(_minFrac);
- destination.setMaximumFractionDigits(_maxFrac);
- }
- } else {
- // Currency rounding
- destination.setMinimumFractionDigits(fractionDigits);
- destination.setMaximumFractionDigits(fractionDigits);
- }
-
- if (incrementDouble > 0.0) {
- BigDecimal incrementBigDecimal;
- BigDecimal _roundingIncrement = properties.getRoundingIncrement();
- if (_roundingIncrement != null) {
- incrementBigDecimal = _roundingIncrement;
- } else {
- incrementBigDecimal = BigDecimal.valueOf(incrementDouble);
- }
- destination.setRoundingIncrement(incrementBigDecimal);
- } else {
- }
- }
-
- private static final ThreadLocal<Properties> threadLocalProperties =
- new ThreadLocal<Properties>() {
- @Override
- protected Properties initialValue() {
- return new Properties();
- }
- };
-
- public static Rounder getCurrencyRounder(DecimalFormatSymbols symbols, IProperties properties) {
- if (SignificantDigitsRounder.useSignificantDigits(properties)) {
- return SignificantDigitsRounder.getInstance(properties);
- }
- Properties cprops = threadLocalProperties.get().clear();
- populateCurrencyRounderProperties(cprops, symbols, properties);
- if (cprops.getRoundingIncrement() != null) {
- return IncrementRounder.getInstance(cprops);
- } else {
- return MagnitudeRounder.getInstance(cprops);
- }
- }
-}
+++ /dev/null
-// © 2017 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html#License
-package com.ibm.icu.impl.number.formatters;
-
-import com.ibm.icu.impl.number.Format;
-import com.ibm.icu.impl.number.Format.BeforeFormat;
-import com.ibm.icu.impl.number.FormatQuantity;
-import com.ibm.icu.impl.number.ModifierHolder;
-import com.ibm.icu.impl.number.Properties;
-
-public class MagnitudeMultiplier extends Format.BeforeFormat {
- private static final MagnitudeMultiplier DEFAULT = new MagnitudeMultiplier(0);
-
- public static interface IProperties {
-
- static int DEFAULT_MAGNITUDE_MULTIPLIER = 0;
-
- /** @see #setMagnitudeMultiplier */
- public int getMagnitudeMultiplier();
-
- /**
- * Multiply all numbers by this power of ten before formatting. Negative multipliers reduce the
- * magnitude and make numbers smaller (closer to zero).
- *
- * @param magnitudeMultiplier The number of powers of ten to scale.
- * @return The property bag, for chaining.
- * @see BigDecimalMultiplier
- */
- public IProperties setMagnitudeMultiplier(int magnitudeMultiplier);
- }
-
- public static boolean useMagnitudeMultiplier(IProperties properties) {
- return properties.getMagnitudeMultiplier() != IProperties.DEFAULT_MAGNITUDE_MULTIPLIER;
- }
-
- // Properties
- final int delta;
-
- public static BeforeFormat getInstance(Properties properties) {
- if (properties.getMagnitudeMultiplier() == 0) {
- return DEFAULT;
- }
- return new MagnitudeMultiplier(properties.getMagnitudeMultiplier());
- }
-
- private MagnitudeMultiplier(int delta) {
- this.delta = delta;
- }
-
- @Override
- public void before(FormatQuantity input, ModifierHolder mods) {
- input.adjustMagnitude(delta);
- }
-
- @Override
- public void export(Properties properties) {
- properties.setMagnitudeMultiplier(delta);
- }
-}
+++ /dev/null
-// © 2017 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html#License
-package com.ibm.icu.impl.number.formatters;
-
-import com.ibm.icu.impl.StandardPlural;
-import com.ibm.icu.impl.number.modifiers.GeneralPluralModifier;
-import com.ibm.icu.impl.number.modifiers.SimpleModifier;
-import com.ibm.icu.text.DecimalFormatSymbols;
-import com.ibm.icu.text.MeasureFormat.FormatWidth;
-import com.ibm.icu.util.MeasureUnit;
-import com.ibm.icu.util.ULocale;
-
-public class MeasureFormat {
-
- public static interface IProperties {
-
- static MeasureUnit DEFAULT_MEASURE_UNIT = null;
-
- /** @see #setMeasureUnit */
- public MeasureUnit getMeasureUnit();
-
- /**
- * Apply prefixes and suffixes for the specified {@link MeasureUnit} to the formatted number.
- *
- * @param measureUnit The measure unit.
- * @return The property bag, for chaining.
- */
- public IProperties setMeasureUnit(MeasureUnit measureUnit);
-
- static FormatWidth DEFAULT_MEASURE_FORMAT_WIDTH = null;
-
- /** @see #setMeasureFormatWidth */
- public FormatWidth getMeasureFormatWidth();
-
- /**
- * Use the specified {@link FormatWidth} when choosing the style of measure unit prefix/suffix.
- *
- * <p>Must be used in conjunction with {@link #setMeasureUnit}.
- *
- * @param measureFormatWidth The width style. Defaults to FormatWidth.WIDE.
- * @return The property bag, for chaining.
- */
- public IProperties setMeasureFormatWidth(FormatWidth measureFormatWidth);
- }
-
- public static boolean useMeasureFormat(IProperties properties) {
- return properties.getMeasureUnit() != IProperties.DEFAULT_MEASURE_UNIT;
- }
-
- public static GeneralPluralModifier getInstance(DecimalFormatSymbols symbols, IProperties properties) {
- ULocale uloc = symbols.getULocale();
- MeasureUnit unit = properties.getMeasureUnit();
- FormatWidth width = properties.getMeasureFormatWidth();
-
- if (unit == null) {
- throw new IllegalArgumentException("A measure unit is required for MeasureFormat");
- }
- if (width == null) {
- width = FormatWidth.WIDE;
- }
-
- // Temporarily, create a MeasureFormat instance for its data loading capability
- // TODO: Move data loading directly into this class file
- com.ibm.icu.text.MeasureFormat mf = com.ibm.icu.text.MeasureFormat.getInstance(uloc, width);
- GeneralPluralModifier mod = new GeneralPluralModifier();
- for (StandardPlural plural : StandardPlural.VALUES) {
- String formatString = null;
- mf.getPluralFormatter(unit, width, plural.ordinal());
- mod.put(plural, new SimpleModifier(formatString, null, false));
- }
- return mod;
- }
-}
+++ /dev/null
-// © 2017 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html#License
-package com.ibm.icu.impl.number.formatters;
-
-import com.ibm.icu.impl.number.Format.AfterFormat;
-import com.ibm.icu.impl.number.ModifierHolder;
-import com.ibm.icu.impl.number.NumberStringBuilder;
-import com.ibm.icu.impl.number.Properties;
-
-public class PaddingFormat implements AfterFormat {
- public enum PadPosition {
- BEFORE_PREFIX,
- AFTER_PREFIX,
- BEFORE_SUFFIX,
- AFTER_SUFFIX;
-
- public static PadPosition fromOld(int old) {
- switch (old) {
- case com.ibm.icu.text.DecimalFormat.PAD_BEFORE_PREFIX:
- return PadPosition.BEFORE_PREFIX;
- case com.ibm.icu.text.DecimalFormat.PAD_AFTER_PREFIX:
- return PadPosition.AFTER_PREFIX;
- case com.ibm.icu.text.DecimalFormat.PAD_BEFORE_SUFFIX:
- return PadPosition.BEFORE_SUFFIX;
- case com.ibm.icu.text.DecimalFormat.PAD_AFTER_SUFFIX:
- return PadPosition.AFTER_SUFFIX;
- default:
- throw new IllegalArgumentException("Don't know how to map " + old);
- }
- }
-
- public int toOld() {
- switch (this) {
- case BEFORE_PREFIX:
- return com.ibm.icu.text.DecimalFormat.PAD_BEFORE_PREFIX;
- case AFTER_PREFIX:
- return com.ibm.icu.text.DecimalFormat.PAD_AFTER_PREFIX;
- case BEFORE_SUFFIX:
- return com.ibm.icu.text.DecimalFormat.PAD_BEFORE_SUFFIX;
- case AFTER_SUFFIX:
- return com.ibm.icu.text.DecimalFormat.PAD_AFTER_SUFFIX;
- default:
- return -1; // silence compiler errors
- }
- }
- }
-
- public static interface IProperties {
-
- static int DEFAULT_FORMAT_WIDTH = 0;
-
- /** @see #setFormatWidth */
- public int getFormatWidth();
-
- /**
- * Sets the minimum width of the string output by the formatting pipeline. For example, if
- * padding is enabled and paddingWidth is set to 6, formatting the number "3.14159" with the
- * pattern "0.00" will result in "··3.14" if '·' is your padding string.
- *
- * <p>If the number is longer than your padding width, the number will display as if no padding
- * width had been specified, which may result in strings longer than the padding width.
- *
- * <p>Width is counted in UTF-16 code units.
- *
- * @param formatWidth The output width.
- * @return The property bag, for chaining.
- * @see #setPadPosition
- * @see #setPadString
- */
- public IProperties setFormatWidth(int formatWidth);
-
- static String DEFAULT_PAD_STRING = null;
-
- /** @see #setPadString */
- public String getPadString();
-
- /**
- * Sets the string used for padding. The string should contain a single character or grapheme
- * cluster.
- *
- * <p>Must be used in conjunction with {@link #setFormatWidth}.
- *
- * @param paddingString The padding string. Defaults to an ASCII space (U+0020).
- * @return The property bag, for chaining.
- * @see #setFormatWidth
- */
- public IProperties setPadString(String paddingString);
-
- static PadPosition DEFAULT_PAD_POSITION = null;
-
- /** @see #setPadPosition */
- public PadPosition getPadPosition();
-
- /**
- * Sets the location where the padding string is to be inserted to maintain the padding width:
- * one of BEFORE_PREFIX, AFTER_PREFIX, BEFORE_SUFFIX, or AFTER_SUFFIX.
- *
- * <p>Must be used in conjunction with {@link #setFormatWidth}.
- *
- * @param padPosition The output width.
- * @return The property bag, for chaining.
- * @see #setFormatWidth
- */
- public IProperties setPadPosition(PadPosition padPosition);
- }
-
- public static final String FALLBACK_PADDING_STRING = "\u0020"; // i.e. a space
-
- public static boolean usePadding(IProperties properties) {
- return properties.getFormatWidth() != IProperties.DEFAULT_FORMAT_WIDTH;
- }
-
- public static AfterFormat getInstance(IProperties properties) {
- return new PaddingFormat(
- properties.getFormatWidth(), properties.getPadString(), properties.getPadPosition());
- }
-
- // Properties
- private final int paddingWidth;
- private final String paddingString;
- private final PadPosition paddingLocation;
-
- private PaddingFormat(int paddingWidth, String paddingString, PadPosition paddingLocation) {
- this.paddingWidth = paddingWidth > 0 ? paddingWidth : 10; // TODO: Is this a sensible default?
- this.paddingString = paddingString != null ? paddingString : FALLBACK_PADDING_STRING;
- this.paddingLocation = paddingLocation != null ? paddingLocation : PadPosition.BEFORE_PREFIX;
- }
-
- @Override
- public int after(ModifierHolder mods, NumberStringBuilder string, int leftIndex, int rightIndex) {
-
- // TODO: Count code points instead of code units?
- // TODO: Make this more efficient (less copying)
- NumberStringBuilder copy1 = new NumberStringBuilder(string);
- ModifierHolder copy2 = mods.createCopy();
- copy2.applyAll(copy1, leftIndex, rightIndex);
- int requiredPadding = paddingWidth - copy1.length();
-
- if (requiredPadding <= 0) {
- // Skip padding, but still apply modifiers to be consistent
- return mods.applyAll(string, leftIndex, rightIndex);
- }
-
- int length = 0;
- if (paddingLocation == PadPosition.AFTER_PREFIX) {
- length += addPadding(requiredPadding, string, leftIndex);
- } else if (paddingLocation == PadPosition.BEFORE_SUFFIX) {
- length += addPadding(requiredPadding, string, rightIndex);
- }
- length += mods.applyAll(string, leftIndex, rightIndex + length);
- if (paddingLocation == PadPosition.BEFORE_PREFIX) {
- length += addPadding(requiredPadding, string, leftIndex);
- } else if (paddingLocation == PadPosition.AFTER_SUFFIX) {
- length += addPadding(requiredPadding, string, rightIndex + length);
- }
-
- return length;
- }
-
- private int addPadding(int requiredPadding, NumberStringBuilder string, int index) {
- for (int i = 0; i < requiredPadding; i++) {
- string.insert(index, paddingString, null);
- }
- return paddingString.length() * requiredPadding;
- }
-
- @Override
- public void export(Properties properties) {
- properties.setFormatWidth(paddingWidth);
- properties.setPadString(paddingString);
- properties.setPadPosition(paddingLocation);
- }
-}
+++ /dev/null
-// © 2017 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html#License
-package com.ibm.icu.impl.number.formatters;
-
-import com.ibm.icu.impl.number.Format;
-import com.ibm.icu.impl.number.FormatQuantity;
-import com.ibm.icu.impl.number.NumberStringBuilder;
-import com.ibm.icu.impl.number.Properties;
-import com.ibm.icu.text.DecimalFormatSymbols;
-import com.ibm.icu.text.NumberFormat;
-import com.ibm.icu.text.NumberFormat.Field;
-
-public class PositiveDecimalFormat implements Format.TargetFormat {
-
- public static interface IProperties extends CurrencyFormat.IProperties {
-
- static int DEFAULT_GROUPING_SIZE = -1;
-
- /** @see #setGroupingSize */
- public int getGroupingSize();
-
- /**
- * Sets the number of digits between grouping separators. For example, the <em>en-US</em> locale
- * uses a grouping size of 3, so the number 1234567 would be formatted as "1,234,567". For
- * locales whose grouping sizes vary with magnitude, see {@link #setSecondaryGroupingSize(int)}.
- *
- * @param groupingSize The primary grouping size.
- * @return The property bag, for chaining.
- */
- public IProperties setGroupingSize(int groupingSize);
-
- static int DEFAULT_SECONDARY_GROUPING_SIZE = -1;
-
- /** @see #setSecondaryGroupingSize */
- public int getSecondaryGroupingSize();
-
- /**
- * Sets the number of digits between grouping separators higher than the least-significant
- * grouping separator. For example, the locale <em>hi</em> uses a primary grouping size of 3 and
- * a secondary grouping size of 2, so the number 1234567 would be formatted as "12,34,567".
- *
- * <p>The two levels of grouping separators can be specified in the pattern string. For example,
- * the <em>hi</em> locale's default decimal format pattern is "#,##,##0.###".
- *
- * @param secondaryGroupingSize The secondary grouping size.
- * @return The property bag, for chaining.
- */
- public IProperties setSecondaryGroupingSize(int secondaryGroupingSize);
-
- static boolean DEFAULT_DECIMAL_SEPARATOR_ALWAYS_SHOWN = false;
-
- /** @see #setDecimalSeparatorAlwaysShown */
- public boolean getDecimalSeparatorAlwaysShown();
-
- /**
- * Sets whether to always show the decimal point, even if the number doesn't require one. For
- * example, if always show decimal is true, the number 123 would be formatted as "123." in
- * locale <em>en-US</em>.
- *
- * @param decimalSeparatorAlwaysShown Whether to show the decimal point when it is optional.
- * @return The property bag, for chaining.
- */
- public IProperties setDecimalSeparatorAlwaysShown(boolean decimalSeparatorAlwaysShown);
-
- static int DEFAULT_MINIMUM_GROUPING_DIGITS = 1;
-
- /** @see #setMinimumGroupingDigits */
- public int getMinimumGroupingDigits();
-
- /**
- * Sets the minimum number of digits required to be beyond the first grouping separator in order
- * to enable grouping. For example, if the minimum grouping digits is 2, then 1234 would be
- * formatted as "1234" but 12345 would be formatted as "12,345" in <em>en-US</em>. Note that
- * 1234567 would still be formatted as "1,234,567", not "1234,567".
- *
- * @param minimumGroupingDigits How many digits must appear before a grouping separator before
- * enabling grouping.
- * @return The property bag, for chaining.
- */
- public IProperties setMinimumGroupingDigits(int minimumGroupingDigits);
- }
-
- public static boolean useGrouping(IProperties properties) {
- return properties.getGroupingSize() != IProperties.DEFAULT_GROUPING_SIZE
- || properties.getSecondaryGroupingSize() != IProperties.DEFAULT_SECONDARY_GROUPING_SIZE;
- }
-
- public static boolean allowsDecimalPoint(IProperties properties) {
- return properties.getDecimalSeparatorAlwaysShown()
- || properties.getMaximumFractionDigits() != 0;
- }
-
- // Properties
- private final boolean alwaysShowDecimal;
- private final int primaryGroupingSize;
- private final int secondaryGroupingSize;
- private final int minimumGroupingDigits;
-
- // Symbols
- private final String infinityString;
- private final String nanString;
- private final String groupingSeparator;
- private final String decimalSeparator;
- private final String[] digitStrings;
- private final int codePointZero;
-
- public PositiveDecimalFormat(DecimalFormatSymbols symbols, IProperties properties) {
- int _primary = properties.getGroupingSize();
- int _secondary = properties.getSecondaryGroupingSize();
- primaryGroupingSize = _primary > 0 ? _primary : _secondary > 0 ? _secondary : 0;
- secondaryGroupingSize = _secondary > 0 ? _secondary : primaryGroupingSize;
-
- minimumGroupingDigits = properties.getMinimumGroupingDigits();
- alwaysShowDecimal = properties.getDecimalSeparatorAlwaysShown();
- infinityString = symbols.getInfinity();
- nanString = symbols.getNaN();
-
- if (CurrencyFormat.useCurrency(properties)) {
- groupingSeparator = symbols.getMonetaryGroupingSeparatorString();
- decimalSeparator = symbols.getMonetaryDecimalSeparatorString();
- } else {
- groupingSeparator = symbols.getGroupingSeparatorString();
- decimalSeparator = symbols.getDecimalSeparatorString();
- }
-
- // Check to see if we can use code points instead of strings
- int _codePointZero = symbols.getCodePointZero();
- if (_codePointZero != -1) {
- // Fast Path (~9% faster than slow path when formatting long strings)
- digitStrings = null;
- codePointZero = _codePointZero;
- } else {
- // Slow Path
- digitStrings = symbols.getDigitStrings(); // makes a copy
- codePointZero = -1;
- }
- }
-
- @Override
- public int target(FormatQuantity input, NumberStringBuilder string, int startIndex) {
- int length = 0;
-
- if (input.isInfinite()) {
- length += string.insert(startIndex, infinityString, NumberFormat.Field.INTEGER);
-
- } else if (input.isNaN()) {
- length += string.insert(startIndex, nanString, NumberFormat.Field.INTEGER);
-
- } else {
- // Add the integer digits
- length += addIntegerDigits(input, string, startIndex);
-
- // Add the decimal point
- if (input.getLowerDisplayMagnitude() < 0 || alwaysShowDecimal) {
- length +=
- string.insert(
- startIndex + length, decimalSeparator, NumberFormat.Field.DECIMAL_SEPARATOR);
- }
-
- // Add the fraction digits
- length += addFractionDigits(input, string, startIndex + length);
- }
-
- return length;
- }
-
- private int addIntegerDigits(FormatQuantity input, NumberStringBuilder string, int startIndex) {
- int length = 0;
- int integerCount = input.getUpperDisplayMagnitude() + 1;
- for (int i = 0; i < integerCount; i++) {
- // Add grouping separator
- if (primaryGroupingSize > 0
- && i == primaryGroupingSize
- && integerCount - i >= minimumGroupingDigits) {
- length +=
- string.insert(startIndex, groupingSeparator, NumberFormat.Field.GROUPING_SEPARATOR);
- } else if (secondaryGroupingSize > 0
- && i > primaryGroupingSize
- && (i - primaryGroupingSize) % secondaryGroupingSize == 0) {
- length +=
- string.insert(startIndex, groupingSeparator, NumberFormat.Field.GROUPING_SEPARATOR);
- }
-
- // Get and append the next digit value
- byte nextDigit = input.getDigit(i);
- length += addDigit(nextDigit, string, startIndex, NumberFormat.Field.INTEGER);
- }
-
- return length;
- }
-
- private int addFractionDigits(FormatQuantity input, NumberStringBuilder string, int index) {
- int length = 0;
- int fractionCount = -input.getLowerDisplayMagnitude();
- for (int i = 0; i < fractionCount; i++) {
- // Get and append the next digit value
- byte nextDigit = input.getDigit(-i - 1);
- length += addDigit(nextDigit, string, index + length, NumberFormat.Field.FRACTION);
- }
- return length;
- }
-
- private int addDigit(byte digit, NumberStringBuilder outputString, int index, Field field) {
- if (codePointZero != -1) {
- return outputString.insertCodePoint(index, codePointZero + digit, field);
- } else {
- return outputString.insert(index, digitStrings[digit], field);
- }
- }
-
- @Override
- public void export(Properties properties) {
- // For backwards compatibility, export 0 as secondary grouping if primary and secondary are the same
- int effectiveSecondaryGroupingSize =
- secondaryGroupingSize == primaryGroupingSize ? 0 : secondaryGroupingSize;
-
- properties.setDecimalSeparatorAlwaysShown(alwaysShowDecimal);
- properties.setGroupingSize(primaryGroupingSize);
- properties.setSecondaryGroupingSize(effectiveSecondaryGroupingSize);
- properties.setMinimumGroupingDigits(minimumGroupingDigits);
- }
-}
+++ /dev/null
-// © 2017 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html#License
-package com.ibm.icu.impl.number.formatters;
-
-import com.ibm.icu.impl.number.FormatQuantity;
-import com.ibm.icu.impl.number.ModifierHolder;
-import com.ibm.icu.impl.number.PNAffixGenerator;
-import com.ibm.icu.impl.number.modifiers.PositiveNegativeAffixModifier;
-import com.ibm.icu.text.DecimalFormatSymbols;
-
-/**
- * The implementation of this class is a thin wrapper around {@link PNAffixGenerator}, a utility
- * used by this and other classes, including {@link CompactDecimalFormat} and {@link Parse}, to
- * efficiently convert from the abstract properties in the property bag to actual prefix and suffix
- * strings.
- */
-
-/**
- * This class is responsible for adding the positive/negative prefixes and suffixes from the decimal
- * format pattern. Properties are set using the following methods:
- *
- * <ul>
- * <li>{@link IProperties#setPositivePrefix(String)}
- * <li>{@link IProperties#setPositiveSuffix(String)}
- * <li>{@link IProperties#setNegativePrefix(String)}
- * <li>{@link IProperties#setNegativeSuffix(String)}
- * <li>{@link IProperties#setPositivePrefixPattern(String)}
- * <li>{@link IProperties#setPositiveSuffixPattern(String)}
- * <li>{@link IProperties#setNegativePrefixPattern(String)}
- * <li>{@link IProperties#setNegativeSuffixPattern(String)}
- * </ul>
- *
- * If one of the first four methods is used (those of the form <code>setXxxYyy</code>), the value
- * will be interpreted literally. If one of the second four methods is used (those of the form
- * <code>setXxxYyyPattern</code>), locale-specific symbols for the plus sign, minus sign, percent
- * sign, permille sign, and currency sign will be substituted into the string, according to Unicode
- * Technical Standard #35 (LDML) section 3.2.
- *
- * <p>Literal characters can be used in the <code>setXxxYyyPattern</code> methods by using quotes;
- * for example, to display a literal "%" sign, you can set the pattern <code>'%'</code>. To display
- * a literal quote, use two quotes in a row, like <code>''</code>.
- *
- * <p>If a value is set in both a <code>setXxxYyy</code> method and in the corresponding <code>
- * setXxxYyyPattern</code> method, the one set in <code>setXxxYyy</code> takes precedence.
- *
- * <p>For more information on formatting currencies, see {@link CurrencyFormat}.
- *
- * <p>The parameter is taken by reference by these methods into the property bag, meaning that if a
- * mutable object like StringBuilder is passed, changes to the StringBuilder will be reflected in
- * the property bag. However, upon creation of a finalized formatter object, all prefixes and
- * suffixes will be converted to strings and will stop reflecting changes in the property bag.
- */
-public class PositiveNegativeAffixFormat {
-
- public static interface IProperties {
-
- static String DEFAULT_POSITIVE_PREFIX = null;
-
- /** @see #setPositivePrefix */
- public String getPositivePrefix();
-
- /**
- * Sets the prefix to prepend to positive numbers. The prefix will be interpreted literally. For
- * example, if you set a positive prefix of <code>p</code>, then the number 123 will be
- * formatted as "p123" in the locale <em>en-US</em>.
- *
- * <p>For more information on prefixes and suffixes, see {@link PositiveNegativeAffixFormat}.
- *
- * @param positivePrefix The CharSequence to prepend to positive numbers.
- * @return The property bag, for chaining.
- * @see PositiveNegativeAffixFormat
- * @see #setPositivePrefixPattern
- */
- public IProperties setPositivePrefix(String positivePrefix);
-
- static String DEFAULT_POSITIVE_SUFFIX = null;
-
- /** @see #setPositiveSuffix */
- public String getPositiveSuffix();
-
- /**
- * Sets the suffix to append to positive numbers. The suffix will be interpreted literally. For
- * example, if you set a positive suffix of <code>p</code>, then the number 123 will be
- * formatted as "123p" in the locale <em>en-US</em>.
- *
- * <p>For more information on prefixes and suffixes, see {@link PositiveNegativeAffixFormat}.
- *
- * @param positiveSuffix The CharSequence to append to positive numbers.
- * @return The property bag, for chaining.
- * @see PositiveNegativeAffixFormat
- * @see #setPositiveSuffixPattern
- */
- public IProperties setPositiveSuffix(String positiveSuffix);
-
- static String DEFAULT_NEGATIVE_PREFIX = null;
-
- /** @see #setNegativePrefix */
- public String getNegativePrefix();
-
- /**
- * Sets the prefix to prepend to negative numbers. The prefix will be interpreted literally. For
- * example, if you set a negative prefix of <code>n</code>, then the number -123 will be
- * formatted as "n123" in the locale <em>en-US</em>. Note that if the negative prefix is left unset,
- * the locale's minus sign is used.
- *
- * <p>For more information on prefixes and suffixes, see {@link PositiveNegativeAffixFormat}.
- *
- * @param negativePrefix The CharSequence to prepend to negative numbers.
- * @return The property bag, for chaining.
- * @see PositiveNegativeAffixFormat
- * @see #setNegativePrefixPattern
- */
- public IProperties setNegativePrefix(String negativePrefix);
-
- static String DEFAULT_NEGATIVE_SUFFIX = null;
-
- /** @see #setNegativeSuffix */
- public String getNegativeSuffix();
-
- /**
- * Sets the suffix to append to negative numbers. The suffix will be interpreted literally. For
- * example, if you set a suffix prefix of <code>n</code>, then the number -123 will be formatted
- * as "-123n" in the locale <em>en-US</em>. Note that the minus sign is prepended by default unless
- * otherwise specified in either the pattern string or in one of the {@link #setNegativePrefix}
- * methods.
- *
- * <p>For more information on prefixes and suffixes, see {@link PositiveNegativeAffixFormat}.
- *
- * @param negativeSuffix The CharSequence to append to negative numbers.
- * @return The property bag, for chaining.
- * @see PositiveNegativeAffixFormat
- * @see #setNegativeSuffixPattern
- */
- public IProperties setNegativeSuffix(String negativeSuffix);
-
- static String DEFAULT_POSITIVE_PREFIX_PATTERN = null;
-
- /** @see #setPositivePrefixPattern */
- public String getPositivePrefixPattern();
-
- /**
- * Sets the prefix to prepend to positive numbers. Locale-specific symbols will be substituted
- * into the string according to Unicode Technical Standard #35 (LDML).
- *
- * <p>For more information on prefixes and suffixes, see {@link PositiveNegativeAffixFormat}.
- *
- * @param positivePrefixPattern The CharSequence to prepend to positive numbers after locale
- * symbol substitutions take place.
- * @return The property bag, for chaining.
- * @see PositiveNegativeAffixFormat
- * @see #setPositivePrefix
- */
- public IProperties setPositivePrefixPattern(String positivePrefixPattern);
-
- static String DEFAULT_POSITIVE_SUFFIX_PATTERN = null;
-
- /** @see #setPositiveSuffixPattern */
- public String getPositiveSuffixPattern();
-
- /**
- * Sets the suffix to append to positive numbers. Locale-specific symbols will be substituted
- * into the string according to Unicode Technical Standard #35 (LDML).
- *
- * <p>For more information on prefixes and suffixes, see {@link PositiveNegativeAffixFormat}.
- *
- * @param positiveSuffixPattern The CharSequence to append to positive numbers after locale
- * symbol substitutions take place.
- * @return The property bag, for chaining.
- * @see PositiveNegativeAffixFormat
- * @see #setPositiveSuffix
- */
- public IProperties setPositiveSuffixPattern(String positiveSuffixPattern);
-
- static String DEFAULT_NEGATIVE_PREFIX_PATTERN = null;
-
- /** @see #setNegativePrefixPattern */
- public String getNegativePrefixPattern();
-
- /**
- * Sets the prefix to prepend to negative numbers. Locale-specific symbols will be substituted
- * into the string according to Unicode Technical Standard #35 (LDML).
- *
- * <p>For more information on prefixes and suffixes, see {@link PositiveNegativeAffixFormat}.
- *
- * @param negativePrefixPattern The CharSequence to prepend to negative numbers after locale
- * symbol substitutions take place.
- * @return The property bag, for chaining.
- * @see PositiveNegativeAffixFormat
- * @see #setNegativePrefix
- */
- public IProperties setNegativePrefixPattern(String negativePrefixPattern);
-
- static String DEFAULT_NEGATIVE_SUFFIX_PATTERN = null;
-
- /** @see #setNegativeSuffixPattern */
- public String getNegativeSuffixPattern();
-
- /**
- * Sets the suffix to append to negative numbers. Locale-specific symbols will be substituted
- * into the string according to Unicode Technical Standard #35 (LDML).
- *
- * <p>For more information on prefixes and suffixes, see {@link PositiveNegativeAffixFormat}.
- *
- * @param negativeSuffixPattern The CharSequence to append to negative numbers after locale
- * symbol substitutions take place.
- * @return The property bag, for chaining.
- * @see PositiveNegativeAffixFormat
- * @see #setNegativeSuffix
- */
- public IProperties setNegativeSuffixPattern(String negativeSuffixPattern);
-
- static boolean DEFAULT_SIGN_ALWAYS_SHOWN = false;
-
- /** @see #setSignAlwaysShown */
- public boolean getSignAlwaysShown();
-
- /**
- * Sets whether to always display of a plus sign on positive numbers.
- *
- * <p>If the location of the negative sign is specified by the decimal format pattern (or by the
- * negative prefix/suffix pattern methods), a plus sign is substituted into that location, in
- * accordance with Unicode Technical Standard #35 (LDML) section 3.2.1. Otherwise, the plus sign
- * is prepended to the number. For example, if the decimal format pattern <code>#;#-</code> is
- * used, then formatting 123 would result in "123+" in the locale <em>en-US</em>.
- *
- * <p>This method should be used <em>instead of</em> setting the positive prefix/suffix. The
- * behavior is undefined if alwaysShowPlusSign is set but the positive prefix/suffix already
- * contains a plus sign.
- *
- * @param plusSignAlwaysShown Whether positive numbers should display a plus sign.
- * @return The property bag, for chaining.
- */
- public IProperties setSignAlwaysShown(boolean plusSignAlwaysShown);
- }
-
- public static PositiveNegativeAffixModifier getInstance(DecimalFormatSymbols symbols, IProperties properties) {
- PNAffixGenerator pnag = PNAffixGenerator.getThreadLocalInstance();
- PNAffixGenerator.Result result = pnag.getModifiers(symbols, properties);
- return new PositiveNegativeAffixModifier(result.positive, result.negative);
- }
-
- // TODO: Investigate static interface methods (Java 8 only?)
- public static void apply(
- FormatQuantity input,
- ModifierHolder mods,
- DecimalFormatSymbols symbols,
- IProperties properties) {
- PNAffixGenerator pnag = PNAffixGenerator.getThreadLocalInstance();
- PNAffixGenerator.Result result = pnag.getModifiers(symbols, properties);
- if (input.isNegative()) {
- mods.add(result.negative);
- } else {
- mods.add(result.positive);
- }
- }
-}
+++ /dev/null
-// © 2017 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html#License
-// THIS CLASS IS A PROOF OF CONCEPT ONLY.
-// IT REQUIRES ADDITIONAL DISCUSION ABOUT ITS DESIGN AND IMPLEMENTATION.
-
-package com.ibm.icu.impl.number.formatters;
-
-import java.util.Deque;
-
-import com.ibm.icu.impl.number.Format;
-import com.ibm.icu.impl.number.FormatQuantity;
-import com.ibm.icu.impl.number.ModifierHolder;
-import com.ibm.icu.impl.number.NumberStringBuilder;
-
-public class RangeFormat extends Format {
- // Primary settings
- private final String separator;
-
- // Child formatters
- private final Format left;
- private final Format right;
-
- public RangeFormat(Format left, Format right, String separator) {
- this.separator = separator; // TODO: This would be loaded from locale data.
- this.left = left;
- this.right = right;
-
- if (left == null || right == null) {
- throw new IllegalArgumentException("Both child formatters are required for RangeFormat");
- }
- }
-
- @Override
- public int process(
- Deque<FormatQuantity> inputs,
- ModifierHolder mods,
- NumberStringBuilder string,
- int startIndex) {
- ModifierHolder lMods = new ModifierHolder();
- ModifierHolder rMods = new ModifierHolder();
- int lLen = left.process(inputs, lMods, string, startIndex);
- int rLen = right.process(inputs, rMods, string, startIndex + lLen);
-
- // Bubble up any modifiers that are shared between the two sides
- while (lMods.peekLast() != null && lMods.peekLast() == rMods.peekLast()) {
- mods.add(lMods.removeLast());
- rMods.removeLast();
- }
-
- // Apply the remaining modifiers
- lLen += lMods.applyAll(string, startIndex, startIndex + lLen);
- rLen += rMods.applyAll(string, startIndex + lLen, startIndex + lLen + rLen);
-
- int sLen = string.insert(startIndex + lLen, separator, null);
-
- return lLen + sLen + rLen;
- }
-}
+++ /dev/null
-// © 2017 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html#License
-package com.ibm.icu.impl.number.formatters;
-
-import com.ibm.icu.impl.number.Rounder;
-import com.ibm.icu.impl.number.Rounder.IBasicRoundingProperties;
-import com.ibm.icu.impl.number.rounders.IncrementRounder;
-import com.ibm.icu.impl.number.rounders.MagnitudeRounder;
-import com.ibm.icu.impl.number.rounders.NoRounder;
-import com.ibm.icu.impl.number.rounders.SignificantDigitsRounder;
-
-// TODO: Figure out a better place to put these methods.
-
-public class RoundingFormat {
-
- public static interface IProperties
- extends IBasicRoundingProperties,
- IncrementRounder.IProperties,
- MagnitudeRounder.IProperties,
- SignificantDigitsRounder.IProperties {}
-
- public static Rounder getDefaultOrNoRounder(IProperties properties) {
- Rounder candidate = getDefaultOrNull(properties);
- if (candidate == null) {
- candidate = NoRounder.getInstance(properties);
- }
- return candidate;
- }
-
- public static Rounder getDefaultOrNull(IProperties properties) {
- if (SignificantDigitsRounder.useSignificantDigits(properties)) {
- return SignificantDigitsRounder.getInstance(properties);
- } else if (IncrementRounder.useRoundingIncrement(properties)) {
- return IncrementRounder.getInstance(properties);
- } else if (MagnitudeRounder.useFractionFormat(properties)) {
- return MagnitudeRounder.getInstance(properties);
- } else {
- return null;
- }
- }
-}
+++ /dev/null
-// © 2017 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html#License
-package com.ibm.icu.impl.number.formatters;
-
-import com.ibm.icu.impl.number.Format;
-import com.ibm.icu.impl.number.FormatQuantity;
-import com.ibm.icu.impl.number.FormatQuantitySelector;
-import com.ibm.icu.impl.number.ModifierHolder;
-import com.ibm.icu.impl.number.Properties;
-import com.ibm.icu.impl.number.Rounder;
-import com.ibm.icu.impl.number.modifiers.ConstantAffixModifier;
-import com.ibm.icu.impl.number.modifiers.PositiveNegativeAffixModifier;
-import com.ibm.icu.impl.number.rounders.IncrementRounder;
-import com.ibm.icu.impl.number.rounders.SignificantDigitsRounder;
-import com.ibm.icu.text.DecimalFormatSymbols;
-import com.ibm.icu.text.NumberFormat;
-
-public class ScientificFormat extends Format.BeforeFormat implements Rounder.MultiplierGenerator {
-
- public static interface IProperties
- extends RoundingFormat.IProperties, CurrencyFormat.IProperties {
-
- static boolean DEFAULT_EXPONENT_SIGN_ALWAYS_SHOWN = false;
-
- /** @see #setExponentSignAlwaysShown */
- public boolean getExponentSignAlwaysShown();
-
- /**
- * Sets whether to show the plus sign in the exponent part of numbers with a zero or positive
- * exponent. For example, the number "1200" with the pattern "0.0E0" would be formatted as
- * "1.2E+3" instead of "1.2E3" in <em>en-US</em>.
- *
- * @param exponentSignAlwaysShown Whether to show the plus sign in positive exponents.
- * @return The property bag, for chaining.
- */
- public IProperties setExponentSignAlwaysShown(boolean exponentSignAlwaysShown);
-
- static int DEFAULT_MINIMUM_EXPONENT_DIGITS = -1;
-
- /** @see #setMinimumExponentDigits */
- public int getMinimumExponentDigits();
-
- /**
- * Sets the minimum number of digits to display in the exponent. For example, the number "1200"
- * with the pattern "0.0E00", which has 2 exponent digits, would be formatted as "1.2E03" in
- * <em>en-US</em>.
- *
- * @param minimumExponentDigits The minimum number of digits to display in the exponent field.
- * @return The property bag, for chaining.
- */
- public IProperties setMinimumExponentDigits(int minimumExponentDigits);
- }
-
- public static boolean useScientificNotation(IProperties properties) {
- return properties.getMinimumExponentDigits() != IProperties.DEFAULT_MINIMUM_EXPONENT_DIGITS;
- }
-
- private static final ThreadLocal<Properties> threadLocalProperties =
- new ThreadLocal<Properties>() {
- @Override
- protected Properties initialValue() {
- return new Properties();
- }
- };
-
- public static ScientificFormat getInstance(DecimalFormatSymbols symbols, IProperties properties) {
- // If significant digits or rounding interval are specified through normal means, we use those.
- // Otherwise, we use the special significant digit rules for scientific notation.
- Rounder rounder;
- if (IncrementRounder.useRoundingIncrement(properties)) {
- rounder = IncrementRounder.getInstance(properties);
- } else if (SignificantDigitsRounder.useSignificantDigits(properties)) {
- rounder = SignificantDigitsRounder.getInstance(properties);
- } else {
- Properties rprops = threadLocalProperties.get().clear();
-
- int minInt = properties.getMinimumIntegerDigits();
- int maxInt = properties.getMaximumIntegerDigits();
- int minFrac = properties.getMinimumFractionDigits();
- int maxFrac = properties.getMaximumFractionDigits();
-
- // If currency is in use, pull information from CurrencyUsage.
- if (CurrencyFormat.useCurrency(properties)) {
- // Use rprops as the vehicle (it is still clean)
- CurrencyFormat.populateCurrencyRounderProperties(rprops, symbols, properties);
- minFrac = rprops.getMinimumFractionDigits();
- maxFrac = rprops.getMaximumFractionDigits();
- rprops.clear();
- }
-
- // TODO: Mark/Andy, take a look at this logic and see if it makes sense to you.
- // I fiddled with the settings and fallbacks to make the unit tests pass, but I
- // don't feel that it's the "right way" to do things.
-
- if (minInt < 0) minInt = 0;
- if (maxInt < minInt) maxInt = minInt;
- if (minFrac < 0) minFrac = 0;
- if (maxFrac < minFrac) maxFrac = minFrac;
-
- rprops.setRoundingMode(properties.getRoundingMode());
-
- if (minInt == 0 && maxFrac == 0) {
- // Special case for the pattern "#E0" with no significant digits specified.
- rprops.setMinimumSignificantDigits(1);
- rprops.setMaximumSignificantDigits(Integer.MAX_VALUE);
- } else if (minInt == 0 && minFrac == 0) {
- // Special case for patterns like "#.##E0" with no significant digits specified.
- rprops.setMinimumSignificantDigits(1);
- rprops.setMaximumSignificantDigits(1 + maxFrac);
- } else {
- rprops.setMinimumSignificantDigits(minInt + minFrac);
- rprops.setMaximumSignificantDigits(minInt + maxFrac);
- }
- rprops.setMinimumIntegerDigits(maxInt == 0 ? 0 : Math.max(1, minInt + minFrac - maxFrac));
- rprops.setMaximumIntegerDigits(maxInt);
- rprops.setMinimumFractionDigits(Math.max(0, minFrac + minInt - maxInt));
- rprops.setMaximumFractionDigits(maxFrac);
- rounder = SignificantDigitsRounder.getInstance(rprops);
- }
-
- return new ScientificFormat(symbols, properties, rounder);
- }
-
- public static ScientificFormat getInstance(
- DecimalFormatSymbols symbols, IProperties properties, Rounder rounder) {
- return new ScientificFormat(symbols, properties, rounder);
- }
-
- // Properties
- private final boolean exponentShowPlusSign;
- private final int exponentDigits;
- private final int minInt;
- private final int maxInt;
- private final int interval;
- private final Rounder rounder;
- private final ConstantAffixModifier separatorMod;
- private final PositiveNegativeAffixModifier signMod;
-
- // Symbols
- private final String[] digitStrings;
-
- private ScientificFormat(DecimalFormatSymbols symbols, IProperties properties, Rounder rounder) {
- exponentShowPlusSign = properties.getExponentSignAlwaysShown();
- exponentDigits = Math.max(1, properties.getMinimumExponentDigits());
-
- // Calculate minInt/maxInt for the purposes of engineering notation:
- // 0 <= minInt <= maxInt < 8
- // The values are validated separately for rounding. This scheme needs to prevent OOM issues
- // (see #13118). Note that the bound 8 on integer digits is historic.
- int _maxInt = properties.getMaximumIntegerDigits();
- int _minInt = properties.getMinimumIntegerDigits();
- // Bug #13289: if maxInt > minInt > 1, then minInt should be 1 for the
- // purposes of engineering notatation.
- if (_maxInt > _minInt && _minInt > 1) {
- _minInt = 1;
- }
- minInt = _minInt < 0 ? 0 : _minInt >= 8 ? 1 : _minInt;
- maxInt = _maxInt < _minInt ? _minInt : _maxInt >= 8 ? _minInt : _maxInt;
- assert 0 <= minInt && minInt <= maxInt && maxInt < 8;
-
- interval = maxInt < 1 ? 1 : maxInt;
- this.rounder = rounder;
- digitStrings = symbols.getDigitStrings(); // makes a copy
-
- separatorMod =
- new ConstantAffixModifier(
- "", symbols.getExponentSeparator(), NumberFormat.Field.EXPONENT_SYMBOL, true);
- signMod =
- new PositiveNegativeAffixModifier(
- new ConstantAffixModifier(
- "",
- exponentShowPlusSign ? symbols.getPlusSignString() : "",
- NumberFormat.Field.EXPONENT_SIGN,
- true),
- new ConstantAffixModifier(
- "", symbols.getMinusSignString(), NumberFormat.Field.EXPONENT_SIGN, true));
- }
-
- private static final ThreadLocal<StringBuilder> threadLocalStringBuilder =
- new ThreadLocal<StringBuilder>() {
- @Override
- protected StringBuilder initialValue() {
- return new StringBuilder();
- }
- };
-
- @Override
- public void before(FormatQuantity input, ModifierHolder mods) {
-
- // Treat zero as if it had magnitude 0
- int exponent;
- if (input.isZero()) {
- rounder.apply(input);
- exponent = 0;
- } else {
- // TODO: Revisit chooseMultiplierAndApply
- exponent = -rounder.chooseMultiplierAndApply(input, this);
- }
-
- // Format the exponent part of the scientific format.
- // Insert digits starting from the left so that append can be used.
- // TODO: Use thread locals here.
- FormatQuantity exponentQ = FormatQuantitySelector.from(exponent);
- StringBuilder exponentSB = threadLocalStringBuilder.get();
- exponentSB.setLength(0);
- exponentQ.setIntegerLength(exponentDigits, Integer.MAX_VALUE);
- exponentQ.setFractionLength(0, 0);
- for (int i = exponentQ.getUpperDisplayMagnitude(); i >= 0; i--) {
- exponentSB.append(digitStrings[exponentQ.getDigit(i)]);
- }
-
- // Add modifiers from the outside in.
- mods.add(
- new ConstantAffixModifier("", exponentSB.toString(), NumberFormat.Field.EXPONENT, true));
- mods.add(signMod.getModifier(exponent < 0));
- mods.add(separatorMod);
- }
-
- @Override
- public int getMultiplier(int magnitude) {
- int digitsShown = ((magnitude % interval + interval) % interval) + 1;
- if (digitsShown < minInt) {
- digitsShown = minInt;
- } else if (digitsShown > maxInt) {
- digitsShown = maxInt;
- }
- int retval = digitsShown - magnitude - 1;
- return retval;
- }
-
- @Override
- public void export(Properties properties) {
- properties.setMinimumExponentDigits(exponentDigits);
- properties.setExponentSignAlwaysShown(exponentShowPlusSign);
-
- // Set the transformed object into the property bag. This may result in a pattern string that
- // uses different syntax from the original, but it will be functionally equivalent.
- rounder.export(properties);
- }
-}
+++ /dev/null
-// © 2017 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html#License
-package com.ibm.icu.impl.number.formatters;
-
-import java.util.Deque;
-
-import com.ibm.icu.impl.number.Format;
-import com.ibm.icu.impl.number.FormatQuantity;
-import com.ibm.icu.impl.number.ModifierHolder;
-import com.ibm.icu.impl.number.NumberStringBuilder;
-import com.ibm.icu.impl.number.Properties;
-
-// TODO: This class isn't currently being used anywhere. Consider removing it.
-
-/** Attaches all prefixes and suffixes at this point in the render tree without bubbling up. */
-public class StrongAffixFormat extends Format implements Format.AfterFormat {
- private final Format child;
-
- public StrongAffixFormat(Format child) {
- this.child = child;
-
- if (child == null) {
- throw new IllegalArgumentException("A child formatter is required for StrongAffixFormat");
- }
- }
-
- @Override
- public int process(
- Deque<FormatQuantity> inputs,
- ModifierHolder mods,
- NumberStringBuilder string,
- int startIndex) {
- int length = child.process(inputs, mods, string, startIndex);
- length += mods.applyAll(string, startIndex, startIndex + length);
- return length;
- }
-
- @Override
- public int after(
- ModifierHolder mods, NumberStringBuilder string, int leftIndex, int rightIndex) {
- return mods.applyAll(string, leftIndex, rightIndex);
- }
-
- @Override
- public void export(Properties properties) {
- // Nothing to do.
- }
-}
import com.ibm.icu.impl.number.Modifier;
import com.ibm.icu.impl.number.Modifier.AffixModifier;
import com.ibm.icu.impl.number.NumberStringBuilder;
-import com.ibm.icu.impl.number.Properties;
import com.ibm.icu.text.NumberFormat.Field;
/** The canonical implementation of {@link Modifier}, containing a prefix and suffix string. */
public String toString() {
return String.format("<ConstantAffixModifier prefix:'%s' suffix:'%s'>", prefix, suffix);
}
-
- @Override
- public void export(Properties properties) {
- throw new UnsupportedOperationException();
- }
}
import com.ibm.icu.impl.number.Modifier;
import com.ibm.icu.impl.number.Modifier.AffixModifier;
import com.ibm.icu.impl.number.NumberStringBuilder;
-import com.ibm.icu.impl.number.Properties;
import com.ibm.icu.text.NumberFormat.Field;
/**
public String toString() {
return String.format("<ConstantMultiFieldModifier prefix:'%s' suffix:'%s'>", prefix, suffix);
}
-
- @Override
- public void export(Properties properties) {
- throw new UnsupportedOperationException();
- }
}
package com.ibm.icu.impl.number.modifiers;
import com.ibm.icu.impl.StandardPlural;
-import com.ibm.icu.impl.number.Format;
-import com.ibm.icu.impl.number.FormatQuantity;
import com.ibm.icu.impl.number.Modifier;
-import com.ibm.icu.impl.number.ModifierHolder;
-import com.ibm.icu.impl.number.Properties;
-import com.ibm.icu.text.PluralRules;
// TODO: Is it okay that this class is not completely immutable? Right now it is internal-only.
// Freezable or Builder could be used if necessary.
+// TODO: This class is currently unused. Probably should be deleted.
+
/**
* A basic implementation of {@link com.ibm.icu.impl.number.Modifier.PositiveNegativePluralModifier}
* that is built on the fly using its <code>put</code> methods.
*/
-public class GeneralPluralModifier extends Format.BeforeFormat
- implements Modifier.PositiveNegativePluralModifier {
+public class GeneralPluralModifier implements Modifier.PositiveNegativePluralModifier {
/**
* A single array for modifiers. Even elements are positive; odd elements are negative. The
* elements 2i and 2i+1 belong to the StandardPlural with ordinal i.
}
return mod;
}
-
- @Override
- public void before(FormatQuantity input, ModifierHolder mods, PluralRules rules) {
- mods.add(getModifier(input.getStandardPlural(rules), input.isNegative()));
- }
-
- @Override
- public void before(FormatQuantity input, ModifierHolder mods) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void export(Properties properties) {
- // Since we can export only one affix pair, do the one for "other".
- Modifier positive = getModifier(StandardPlural.OTHER, false);
- Modifier negative = getModifier(StandardPlural.OTHER, true);
- PositiveNegativeAffixModifier.exportPositiveNegative(properties, positive, negative);
- }
}
// License & terms of use: http://www.unicode.org/copyright.html#License
package com.ibm.icu.impl.number.modifiers;
-import com.ibm.icu.impl.number.Format;
-import com.ibm.icu.impl.number.FormatQuantity;
import com.ibm.icu.impl.number.Modifier;
import com.ibm.icu.impl.number.Modifier.AffixModifier;
-import com.ibm.icu.impl.number.ModifierHolder;
-import com.ibm.icu.impl.number.Properties;
+
+// TODO: This class is currently unused. Should probably be deleted.
/** A class containing a positive form and a negative form of {@link ConstantAffixModifier}. */
-public class PositiveNegativeAffixModifier extends Format.BeforeFormat
- implements Modifier.PositiveNegativeModifier {
+public class PositiveNegativeAffixModifier implements Modifier.PositiveNegativeModifier {
private final AffixModifier positive;
private final AffixModifier negative;
public Modifier getModifier(boolean isNegative) {
return isNegative ? negative : positive;
}
-
- @Override
- public void before(FormatQuantity input, ModifierHolder mods) {
- Modifier mod = getModifier(input.isNegative());
- mods.add(mod);
- }
-
- @Override
- public void export(Properties properties) {
- exportPositiveNegative(properties, positive, negative);
- }
-
- /** Internal method used to export a positive and negative modifier to a property bag. */
- static void exportPositiveNegative(Properties properties, Modifier positive, Modifier negative) {
- properties.setPositivePrefix(positive.getPrefix().isEmpty() ? null : positive.getPrefix());
- properties.setPositiveSuffix(positive.getSuffix().isEmpty() ? null : positive.getSuffix());
- properties.setNegativePrefix(negative.getPrefix().isEmpty() ? null : negative.getPrefix());
- properties.setNegativeSuffix(negative.getSuffix().isEmpty() ? null : negative.getSuffix());
- }
}
import com.ibm.icu.impl.SimpleFormatterImpl;
import com.ibm.icu.impl.number.Modifier;
import com.ibm.icu.impl.number.NumberStringBuilder;
-import com.ibm.icu.impl.number.Properties;
import com.ibm.icu.text.NumberFormat.Field;
/**
}
}
}
-
- @Override
- public void export(Properties properties) {
- throw new UnsupportedOperationException();
- }
}
+++ /dev/null
-// © 2017 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html#License
-package com.ibm.icu.impl.number.rounders;
-
-import java.math.BigDecimal;
-
-import com.ibm.icu.impl.number.FormatQuantity;
-import com.ibm.icu.impl.number.Properties;
-import com.ibm.icu.impl.number.Rounder;
-
-public class IncrementRounder extends Rounder {
-
- public static interface IProperties extends IBasicRoundingProperties {
-
- static BigDecimal DEFAULT_ROUNDING_INCREMENT = null;
-
- /** @see #setRoundingIncrement */
- public BigDecimal getRoundingIncrement();
-
- /**
- * Sets the increment to which to round numbers. For example, with a rounding interval of 0.05,
- * the number 11.17 would be formatted as "11.15" in locale <em>en-US</em> with the default
- * rounding mode.
- *
- * <p>You can use either a rounding increment or significant digits, but not both at the same
- * time.
- *
- * <p>The rounding increment can be specified in a pattern string. For example, the pattern
- * "#,##0.05" corresponds to a rounding interval of 0.05 with 1 minimum integer digit and a
- * grouping size of 3.
- *
- * @param roundingIncrement The interval to which to round.
- * @return The property bag, for chaining.
- */
- public IProperties setRoundingIncrement(BigDecimal roundingIncrement);
- }
-
- public static boolean useRoundingIncrement(IProperties properties) {
- return properties.getRoundingIncrement() != IProperties.DEFAULT_ROUNDING_INCREMENT;
- }
-
- private final BigDecimal roundingIncrement;
-
- public static IncrementRounder getInstance(IProperties properties) {
- return new IncrementRounder(properties);
- }
-
- private IncrementRounder(IProperties properties) {
- super(properties);
- if (properties.getRoundingIncrement().compareTo(BigDecimal.ZERO) <= 0) {
- throw new IllegalArgumentException("Rounding interval must be greater than zero");
- }
- roundingIncrement = properties.getRoundingIncrement();
- }
-
- @Override
- public void apply(FormatQuantity input) {
- input.roundToIncrement(roundingIncrement, mathContext);
- applyDefaults(input);
- }
-
- @Override
- public void export(Properties properties) {
- super.export(properties);
- properties.setRoundingIncrement(roundingIncrement);
- }
-}
+++ /dev/null
-// © 2017 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html#License
-package com.ibm.icu.impl.number.rounders;
-
-import com.ibm.icu.impl.number.FormatQuantity;
-import com.ibm.icu.impl.number.Rounder;
-
-public class MagnitudeRounder extends Rounder {
-
- public static interface IProperties extends IBasicRoundingProperties {}
-
- public static boolean useFractionFormat(IProperties properties) {
- return properties.getMinimumFractionDigits() != IProperties.DEFAULT_MINIMUM_FRACTION_DIGITS
- || properties.getMaximumFractionDigits() != IProperties.DEFAULT_MAXIMUM_FRACTION_DIGITS;
- }
-
- public static MagnitudeRounder getInstance(IBasicRoundingProperties properties) {
- return new MagnitudeRounder(properties);
- }
-
- private MagnitudeRounder(IBasicRoundingProperties properties) {
- super(properties);
- }
-
- @Override
- public void apply(FormatQuantity input) {
- input.roundToMagnitude(-maxFrac, mathContext);
- applyDefaults(input);
- }
-}
+++ /dev/null
-// © 2017 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html#License
-package com.ibm.icu.impl.number.rounders;
-
-import com.ibm.icu.impl.number.FormatQuantity;
-import com.ibm.icu.impl.number.Rounder;
-
-/** Sets the integer and fraction length based on the properties, but does not perform rounding. */
-public final class NoRounder extends Rounder {
-
- public static NoRounder getInstance(IBasicRoundingProperties properties) {
- return new NoRounder(properties);
- }
-
- private NoRounder(IBasicRoundingProperties properties) {
- super(properties);
- }
-
- @Override
- public void apply(FormatQuantity input) {
- applyDefaults(input);
- input.roundToInfinity();
- }
-}
+++ /dev/null
-// © 2017 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html#License
-package com.ibm.icu.impl.number.rounders;
-
-import java.math.RoundingMode;
-
-import com.ibm.icu.impl.number.FormatQuantity;
-import com.ibm.icu.impl.number.Properties;
-import com.ibm.icu.impl.number.Rounder;
-
-public class SignificantDigitsRounder extends Rounder {
-
- public static interface IProperties extends Rounder.IBasicRoundingProperties {
-
- static int DEFAULT_MINIMUM_SIGNIFICANT_DIGITS = -1;
-
- /** @see #setMinimumSignificantDigits */
- public int getMinimumSignificantDigits();
-
- /**
- * Sets the minimum number of significant digits to display. If, after rounding to the number of
- * significant digits specified by {@link #setMaximumSignificantDigits}, the number of remaining
- * significant digits is less than the minimum, the number will be padded with zeros. For
- * example, if minimum significant digits is 3, the number 5.8 will be formatted as "5.80" in
- * locale <em>en-US</em>. Note that minimum significant digits is relevant only when numbers
- * have digits after the decimal point.
- *
- * <p>If both minimum significant digits and minimum integer/fraction digits are set at the same
- * time, both values will be respected, and the one that results in the greater number of
- * padding zeros will be used. For example, formatting the number 73 with 3 minimum significant
- * digits and 2 minimum fraction digits will produce "73.00".
- *
- * <p>The number of significant digits can be specified in a pattern string using the '@'
- * character. For example, the pattern "@@#" corresponds to a minimum of 2 and a maximum of 3
- * significant digits.
- *
- * @param minimumSignificantDigits The minimum number of significant digits to display.
- * @return The property bag, for chaining.
- */
- public IProperties setMinimumSignificantDigits(int minimumSignificantDigits);
-
- static int DEFAULT_MAXIMUM_SIGNIFICANT_DIGITS = -1;
-
- /** @see #setMaximumSignificantDigits */
- public int getMaximumSignificantDigits();
-
- /**
- * Sets the maximum number of significant digits to display. The number of significant digits is
- * equal to the number of digits counted from the leftmost nonzero digit through the rightmost
- * nonzero digit; for example, the number "2010" has 3 significant digits. If the number has
- * more significant digits than specified here, the extra significant digits will be rounded off
- * using the rounding mode specified by {@link #setRoundingMode(RoundingMode)}. For example, if
- * maximum significant digits is 3, the number 1234.56 will be formatted as "1230" in locale
- * <em>en-US</em> with the default rounding mode.
- *
- * <p>If both maximum significant digits and maximum integer/fraction digits are set at the same
- * time, the behavior is undefined.
- *
- * <p>The number of significant digits can be specified in a pattern string using the '@'
- * character. For example, the pattern "@@#" corresponds to a minimum of 2 and a maximum of 3
- * significant digits.
- *
- * @param maximumSignificantDigits The maximum number of significant digits to display.
- * @return The property bag, for chaining.
- */
- public IProperties setMaximumSignificantDigits(int maximumSignificantDigits);
- }
-
- public static boolean useSignificantDigits(IProperties properties) {
- return properties.getMinimumSignificantDigits()
- != IProperties.DEFAULT_MINIMUM_SIGNIFICANT_DIGITS
- || properties.getMaximumSignificantDigits()
- != IProperties.DEFAULT_MAXIMUM_SIGNIFICANT_DIGITS;
- }
-
- public static SignificantDigitsRounder getInstance(IProperties properties) {
- return new SignificantDigitsRounder(properties);
- }
-
- private final int minSig;
- private final int maxSig;
-
- private SignificantDigitsRounder(IProperties properties) {
- super(properties);
- int _minSig = properties.getMinimumSignificantDigits();
- int _maxSig = properties.getMaximumSignificantDigits();
- minSig = _minSig < 1 ? 1 : _minSig > 1000 ? 1000 : _minSig;
- maxSig = _maxSig < 0 ? 1000 : _maxSig < minSig ? minSig : _maxSig > 1000 ? 1000 : _maxSig;
- }
-
- @Override
- public void apply(FormatQuantity input) {
-
- int magnitude, effectiveMag, magMinSig, magMaxSig;
-
- if (input.isZero()) {
- // Treat zero as if magnitude corresponded to the minimum number of zeros
- magnitude = minInt - 1;
- } else {
- magnitude = input.getMagnitude();
- }
- effectiveMag = Math.min(magnitude + 1, maxInt);
- magMinSig = effectiveMag - minSig;
- magMaxSig = effectiveMag - maxSig;
-
- // Step 1: pick the rounding magnitude and apply.
- int roundingMagnitude = magMaxSig;
- input.roundToMagnitude(roundingMagnitude, mathContext);
-
- // In case magnitude changed:
- if (input.isZero()) {
- magnitude = minInt - 1;
- } else {
- magnitude = input.getMagnitude();
- }
- effectiveMag = Math.min(magnitude + 1, maxInt);
- magMinSig = effectiveMag - minSig;
- magMaxSig = effectiveMag - maxSig;
-
- // Step 2: pick the number of visible digits.
- input.setIntegerLength(minInt, maxInt);
- input.setFractionLength(Math.max(minFrac, -magMinSig), Integer.MAX_VALUE);
- }
-
- @Override
- public void export(Properties properties) {
- super.export(properties);
- properties.setMinimumSignificantDigits(minSig);
- properties.setMaximumSignificantDigits(maxSig);
- }
-}
import com.ibm.icu.impl.number.Parse;
import com.ibm.icu.impl.number.PatternString;
import com.ibm.icu.impl.number.Properties;
-import com.ibm.icu.impl.number.formatters.PaddingFormat.PadPosition;
-import com.ibm.icu.impl.number.formatters.PositiveDecimalFormat;
-import com.ibm.icu.impl.number.formatters.ScientificFormat;
-import com.ibm.icu.impl.number.rounders.SignificantDigitsRounder;
+import com.ibm.icu.impl.number.ThingsNeedingNewHome;
+import com.ibm.icu.impl.number.ThingsNeedingNewHome.PadPosition;
import com.ibm.icu.lang.UCharacter;
import com.ibm.icu.math.BigDecimal;
import com.ibm.icu.math.MathContext;
* @stable ICU 3.0
*/
public synchronized boolean areSignificantDigitsUsed() {
- return SignificantDigitsRounder.useSignificantDigits(properties);
+ return properties.getMinimumSignificantDigits() != -1
+ || properties.getMaximumSignificantDigits() != -1;
}
/**
properties.setMinimumSignificantDigits(1);
properties.setMaximumSignificantDigits(6);
} else {
- properties.setMinimumSignificantDigits(Properties.DEFAULT_MINIMUM_SIGNIFICANT_DIGITS);
- properties.setMaximumSignificantDigits(Properties.DEFAULT_MAXIMUM_SIGNIFICANT_DIGITS);
+ properties.setMinimumSignificantDigits(-1);
+ properties.setMaximumSignificantDigits(-1);
}
refreshFormatter();
}
* @stable ICU 2.0
*/
public synchronized boolean isScientificNotation() {
- return ScientificFormat.useScientificNotation(properties);
+ return properties.getMinimumExponentDigits() != -1;
}
/**
if (useScientific) {
properties.setMinimumExponentDigits(1);
} else {
- properties.setMinimumExponentDigits(Properties.DEFAULT_MINIMUM_EXPONENT_DIGITS);
+ properties.setMinimumExponentDigits(-1);
}
refreshFormatter();
}
*/
@Override
public synchronized boolean isGroupingUsed() {
- return PositiveDecimalFormat.useGrouping(properties);
+ return properties.getGroupingSize() != -1 || properties.getSecondaryGroupingSize() != -1;
}
/**
// Set to a reasonable default value
properties.setGroupingSize(3);
} else {
- properties.setGroupingSize(Properties.DEFAULT_GROUPING_SIZE);
- properties.setSecondaryGroupingSize(Properties.DEFAULT_SECONDARY_GROUPING_SIZE);
+ properties.setGroupingSize(-1);
+ properties.setSecondaryGroupingSize(-1);
}
refreshFormatter();
}
*/
@Deprecated
public synchronized int getMinimumGroupingDigits() {
- return properties.getMinimumGroupingDigits();
+ // Only 1 and 2 are supported right now.
+ if (properties.getMinimumGroupingDigits() == 2) {
+ return 2;
+ } else {
+ return 1;
+ }
}
/**
// so that CurrencyUsage is reflected properly.
// TODO: Consider putting this logic in PatternString.java instead.
Properties tprops = threadLocalProperties.get().copyFrom(properties);
- if (com.ibm.icu.impl.number.formatters.CurrencyFormat.useCurrency(properties)) {
+ if (ThingsNeedingNewHome.useCurrency(properties)) {
tprops.setMinimumFractionDigits(exportedProperties.getMinimumFractionDigits());
tprops.setMaximumFractionDigits(exportedProperties.getMaximumFractionDigits());
tprops.setRoundingIncrement(exportedProperties.getRoundingIncrement());
import java.util.Arrays;
import java.util.Locale;
-import com.ibm.icu.impl.number.FormatQuantityBCD;
+import com.ibm.icu.impl.number.FormatQuantity;
import com.ibm.icu.impl.number.NumberStringBuilder;
-import com.ibm.icu.impl.number.formatters.PaddingFormat.PadPosition;
+import com.ibm.icu.impl.number.ThingsNeedingNewHome.PadPosition;
import com.ibm.icu.text.CompactDecimalFormat.CompactStyle;
import com.ibm.icu.text.DecimalFormatSymbols;
import com.ibm.icu.text.MeasureFormat.FormatWidth;
public static class NumberFormatterResult {
NumberStringBuilder nsb;
- FormatQuantityBCD fq;
+ FormatQuantity fq;
MicroProps micros;
/**
* @deprecated This API is ICU internal only.
*/
@Deprecated
- public NumberFormatterResult(NumberStringBuilder nsb, FormatQuantityBCD fq, MicroProps micros) {
+ public NumberFormatterResult(NumberStringBuilder nsb, FormatQuantity fq, MicroProps micros) {
this.nsb = nsb;
this.fq = fq;
this.micros = micros;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
+import com.ibm.icu.impl.number.FormatQuantity;
import com.ibm.icu.impl.number.FormatQuantity4;
-import com.ibm.icu.impl.number.FormatQuantityBCD;
import com.ibm.icu.impl.number.NumberStringBuilder;
import com.ibm.icu.impl.number.PatternString;
import com.ibm.icu.impl.number.Properties;
* @param fq The quantity to be formatted.
* @return The formatted number result.
*/
- private NumberFormatterResult format(FormatQuantityBCD fq) {
+ public NumberFormatterResult format(FormatQuantity fq) {
MacroProps macros = resolve();
NumberStringBuilder string = new NumberStringBuilder();
long currentCount = callCount.incrementAndGet(this);
/** @author sffc */
public final class NumberPropertyMapper {
+ /** Convenience method to create a NumberFormatterImpl directly. */
+ public static NumberFormatterImpl create(
+ Properties properties, DecimalFormatSymbols symbols, ULocale uloc) {
+ MacroProps macros = oldToNew(properties, symbols, null);
+ return NumberFormatterImpl.fromMacros(macros).locale(uloc);
+ }
+
/**
* Creates a new {@link MacroProps} object based on the content of a {@link Properties} object. In
* other words, maps Properties to MacroProps. This function is used by the JDK-compatibility API
|| affixProvider.hasCurrencySign());
Currency currency = CustomSymbolCurrency.resolve(properties.getCurrency(), locale, symbols);
CurrencyUsage currencyUsage = properties.getCurrencyUsage();
- boolean explicitCurrencyUsage = currencyUsage != Properties.DEFAULT_CURRENCY_USAGE;
+ boolean explicitCurrencyUsage = currencyUsage != null;
if (!explicitCurrencyUsage) {
currencyUsage = CurrencyUsage.STANDARD;
}
int maxSig = properties.getMaximumSignificantDigits();
BigDecimal roundingIncrement = properties.getRoundingIncrement();
MathContext mathContext = RoundingUtils.getMathContextOrUnlimited(properties);
- boolean explicitMinMaxFrac =
- minFrac != Properties.DEFAULT_MINIMUM_FRACTION_DIGITS
- || maxFrac != Properties.DEFAULT_MAXIMUM_FRACTION_DIGITS;
- boolean explicitMinMaxSig =
- minSig != Properties.DEFAULT_MINIMUM_SIGNIFICANT_DIGITS
- || maxSig != Properties.DEFAULT_MAXIMUM_SIGNIFICANT_DIGITS;
+ boolean explicitMinMaxFrac = minFrac != -1 || maxFrac != -1;
+ boolean explicitMinMaxSig = minSig != -1 || maxSig != -1;
// Validate min/max int/frac.
// For backwards compatibility, minimum overrides maximum if the two conflict.
// The following logic ensures that there is always a minimum of at least one digit.
// PADDING //
/////////////
- if (properties.getFormatWidth() != Properties.DEFAULT_FORMAT_WIDTH) {
+ if (properties.getFormatWidth() != -1) {
macros.padding =
PaddingImpl.getInstance(
properties.getPadString(), properties.getFormatWidth(), properties.getPadPosition());
// SCIENTIFIC NOTATION //
/////////////////////////
- if (properties.getMinimumExponentDigits() != Properties.DEFAULT_MINIMUM_EXPONENT_DIGITS) {
+ if (properties.getMinimumExponentDigits() != -1) {
// Scientific notation is required.
// The mapping from property bag to scientific notation is nontrivial due to LDML rules.
// The maximum of 8 engineering digits has unknown origins and is not in the spec.
int engineering =
(maxInt != Integer.MAX_VALUE) ? maxInt : properties.getMaximumIntegerDigits();
engineering = (engineering < 0) ? 0 : (engineering > 8) ? minInt : engineering;
+ // Bug #13289: if maxInt > minInt > 1, then minInt should be 1.
+ // Clear out IntegerWidth to prevent padding extra zeros.
+ if (maxInt > minInt && minInt > 1) {
+ macros.integerWidth = null;
+ }
macros.notation =
new NotationScientificImpl(
// Engineering interval:
// Minimum exponent digits:
properties.getMinimumExponentDigits(),
// Exponent sign always shown:
- properties.getExponentSignAlwaysShown()
- ? SignDisplay.ALWAYS
- : SignDisplay.AUTO);
+ properties.getExponentSignAlwaysShown() ? SignDisplay.ALWAYS : SignDisplay.AUTO);
// Scientific notation also involves overriding the rounding mode.
if (macros.rounding instanceof RoundingImplFraction) {
int minInt_ = properties.getMinimumIntegerDigits();
// COMPACT NOTATION //
//////////////////////
- if (properties.getCompactStyle() != Properties.DEFAULT_COMPACT_STYLE) {
+ if (properties.getCompactStyle() != null) {
if (properties.getCompactCustomData() != null) {
macros.notation = new NotationImpl.NotationCompactImpl(properties.getCompactCustomData());
} else if (properties.getCompactStyle() == CompactStyle.LONG) {
// MULTIPLIERS //
/////////////////
- if (properties.getMagnitudeMultiplier() != Properties.DEFAULT_MAGNITUDE_MULTIPLIER) {
+ if (properties.getMagnitudeMultiplier() != 0) {
macros.multiplier = new MultiplierImpl(properties.getMagnitudeMultiplier());
- } else if (properties.getMultiplier() != Properties.DEFAULT_MULTIPLIER) {
+ } else if (properties.getMultiplier() != null) {
macros.multiplier = new MultiplierImpl(properties.getMultiplier());
}
package newapi.impl;
import com.ibm.icu.impl.number.NumberStringBuilder;
-import com.ibm.icu.impl.number.formatters.PaddingFormat.PadPosition;
+import com.ibm.icu.impl.number.ThingsNeedingNewHome.PadPosition;
import newapi.NumberFormatter.Padding;
package newapi.impl;
// License & terms of use: http://www.unicode.org/copyright.html#License
-import com.ibm.icu.impl.number.Format;
import com.ibm.icu.impl.number.FormatQuantity;
import com.ibm.icu.impl.number.NumberStringBuilder;
-import com.ibm.icu.impl.number.Properties;
import com.ibm.icu.text.NumberFormat;
import newapi.NumberFormatter.DecimalMarkDisplay;
-public class PositiveDecimalImpl implements Format.TargetFormat {
+public class PositiveDecimalImpl {
- @Override
- public int target(FormatQuantity input, NumberStringBuilder string, int startIndex) {
- // FIXME
- throw new UnsupportedOperationException();
- }
-
- /**
- * @param micros
- * @param fq
- * @param output
- * @return
- */
public static int apply(MicroProps micros, FormatQuantity input, NumberStringBuilder string) {
int length = 0;
if (input.isInfinite()) {
}
return length;
}
-
- @Override
- public void export(Properties properties) {
- throw new UnsupportedOperationException();
- }
}
import java.math.MathContext;
import java.math.RoundingMode;
-import com.ibm.icu.impl.number.formatters.PaddingFormat.PadPosition;
+import com.ibm.icu.impl.number.ThingsNeedingNewHome.PadPosition;
import com.ibm.icu.text.CompactDecimalFormat.CompactStyle;
import com.ibm.icu.text.DecimalFormatSymbols;
import com.ibm.icu.text.MeasureFormat.FormatWidth;
if (c1 == ',') {
char c2 = safeCharAt(skeleton, offset++);
char c3 = safeCharAt(skeleton, offset++);
- result = GroupingImpl.getInstance((short) (c0 - '0'), (short) (c2 - '0'), c3 == '&');
+ result = GroupingImpl.getInstance((byte) (c0 - '0'), (byte) (c2 - '0'), c3 == '&');
} else {
- result = GroupingImpl.getInstance((short) (c0 - '0'), (short) (c0 - '0'), c1 == '&');
+ result = GroupingImpl.getInstance((byte) (c0 - '0'), (byte) (c0 - '0'), c1 == '&');
}
} else {
StringBuilder sb = new StringBuilder();
// Treat max int digits > 8 as being the same as min int digits.
// This behavior is not spelled out in the specification.
// JDK fails here because it tries to use 9 + 6 = 15 sig digits.
-// C and J get 29.979246E7
-2 9 1 6 2.9979246E8 CJK
+2 9 1 6 29.979246E7 K
test significant digits scientific
set locale en
import java.math.BigDecimal;
import java.math.RoundingMode;
-import java.text.ParseException;
import java.text.ParsePosition;
import org.junit.Test;
import com.ibm.icu.dev.test.TestUtil;
-import com.ibm.icu.impl.number.Endpoint;
-import com.ibm.icu.impl.number.Format;
-import com.ibm.icu.impl.number.FormatQuantity;
-import com.ibm.icu.impl.number.FormatQuantity1;
-import com.ibm.icu.impl.number.FormatQuantity2;
-import com.ibm.icu.impl.number.FormatQuantity3;
-import com.ibm.icu.impl.number.FormatQuantity4;
-import com.ibm.icu.impl.number.Parse;
import com.ibm.icu.impl.number.Parse.ParseMode;
import com.ibm.icu.impl.number.PatternString;
import com.ibm.icu.impl.number.Properties;
-import com.ibm.icu.impl.number.formatters.PaddingFormat.PadPosition;
-import com.ibm.icu.text.DecimalFormat;
-import com.ibm.icu.text.DecimalFormat.PropertySetter;
+import com.ibm.icu.impl.number.ThingsNeedingNewHome.PadPosition;
import com.ibm.icu.text.DecimalFormatSymbols;
import com.ibm.icu.text.DecimalFormat_ICU58;
import com.ibm.icu.util.CurrencyAmount;
}
};
- private DataDrivenNumberFormatTestUtility.CodeUnderTest ICU59 =
- new DataDrivenNumberFormatTestUtility.CodeUnderTest() {
-
- @Override
- public Character Id() {
- return 'S';
- }
-
- /**
- * Runs a single formatting test. On success, returns null. On failure, returns the error.
- * This implementation just returns null. Subclasses should override.
- *
- * @param tuple contains the parameters of the format test.
- */
- @Override
- public String format(DataDrivenNumberFormatTestData tuple) {
- String pattern = (tuple.pattern == null) ? "0" : tuple.pattern;
- ULocale locale = (tuple.locale == null) ? ULocale.ENGLISH : tuple.locale;
- Properties properties =
- PatternString.parseToProperties(
- pattern,
- tuple.currency != null
- ? PatternString.IGNORE_ROUNDING_ALWAYS
- : PatternString.IGNORE_ROUNDING_NEVER);
- propertiesFromTuple(tuple, properties);
- Format fmt = Endpoint.fromBTA(properties, locale);
- FormatQuantity q1, q2, q3;
- if (tuple.format.equals("NaN")) {
- q1 = q2 = new FormatQuantity1(Double.NaN);
- q3 = new FormatQuantity2(Double.NaN);
- } else if (tuple.format.equals("-Inf")) {
- q1 = q2 = new FormatQuantity1(Double.NEGATIVE_INFINITY);
- q3 = new FormatQuantity1(Double.NEGATIVE_INFINITY);
- } else if (tuple.format.equals("Inf")) {
- q1 = q2 = new FormatQuantity1(Double.POSITIVE_INFINITY);
- q3 = new FormatQuantity1(Double.POSITIVE_INFINITY);
- } else {
- BigDecimal d = new BigDecimal(tuple.format);
- if (d.precision() <= 16) {
- q1 = new FormatQuantity1(d);
- q2 = new FormatQuantity1(Double.parseDouble(tuple.format));
- q3 = new FormatQuantity4(d);
- } else {
- q1 = new FormatQuantity1(d);
- q2 = new FormatQuantity3(d);
- q3 = new FormatQuantity4(d); // duplicate values so no null
- }
- }
- String expected = tuple.output;
- String actual1 = fmt.format(q1);
- if (!expected.equals(actual1)) {
- return "Expected \""
- + expected
- + "\", got \""
- + actual1
- + "\" on FormatQuantity1 BigDecimal";
- }
- String actual2 = fmt.format(q2);
- if (!expected.equals(actual2)) {
- return "Expected \""
- + expected
- + "\", got \""
- + actual2
- + "\" on FormatQuantity1 double";
- }
- String actual3 = fmt.format(q3);
- if (!expected.equals(actual3)) {
- return "Expected \""
- + expected
- + "\", got \""
- + actual3
- + "\" on FormatQuantity4 BigDecimal";
- }
- return null;
- }
-
- /**
- * Runs a single toPattern test. On success, returns null. On failure, returns the error.
- * This implementation just returns null. Subclasses should override.
- *
- * @param tuple contains the parameters of the format test.
- */
- @Override
- public String toPattern(DataDrivenNumberFormatTestData tuple) {
- String pattern = (tuple.pattern == null) ? "0" : tuple.pattern;
- final Properties properties;
- DecimalFormat df;
- try {
- properties =
- PatternString.parseToProperties(
- pattern,
- tuple.currency != null
- ? PatternString.IGNORE_ROUNDING_ALWAYS
- : PatternString.IGNORE_ROUNDING_NEVER);
- propertiesFromTuple(tuple, properties);
- // TODO: Use PatternString.propertiesToString() directly. (How to deal with CurrencyUsage?)
- df = new DecimalFormat();
- df.setProperties(
- new PropertySetter() {
- @Override
- public void set(Properties props) {
- props.copyFrom(properties);
- }
- });
- } catch (IllegalArgumentException e) {
- e.printStackTrace();
- return e.getLocalizedMessage();
- }
-
- if (tuple.toPattern != null) {
- String expected = tuple.toPattern;
- String actual = df.toPattern();
- if (!expected.equals(actual)) {
- return "Expected toPattern='" + expected + "'; got '" + actual + "'";
- }
- }
- if (tuple.toLocalizedPattern != null) {
- String expected = tuple.toLocalizedPattern;
- String actual = PatternString.propertiesToString(properties);
- if (!expected.equals(actual)) {
- return "Expected toLocalizedPattern='" + expected + "'; got '" + actual + "'";
- }
- }
- return null;
- }
-
- /**
- * Runs a single parse test. On success, returns null. On failure, returns the error. This
- * implementation just returns null. Subclasses should override.
- *
- * @param tuple contains the parameters of the format test.
- */
- @Override
- public String parse(DataDrivenNumberFormatTestData tuple) {
- String pattern = (tuple.pattern == null) ? "0" : tuple.pattern;
- Properties properties;
- ParsePosition ppos = new ParsePosition(0);
- Number actual;
- try {
- properties =
- PatternString.parseToProperties(
- pattern,
- tuple.currency != null
- ? PatternString.IGNORE_ROUNDING_ALWAYS
- : PatternString.IGNORE_ROUNDING_NEVER);
- propertiesFromTuple(tuple, properties);
- actual =
- Parse.parse(
- tuple.parse, ppos, properties, DecimalFormatSymbols.getInstance(tuple.locale));
- } catch (IllegalArgumentException e) {
- return "parse exception: " + e.getMessage();
- }
- if (actual == null && ppos.getIndex() != 0) {
- throw new AssertionError("Error: value is null but parse position is not zero");
- }
- if (ppos.getIndex() == 0) {
- return "Parse failed; got " + actual + ", but expected " + tuple.output;
- }
- if (tuple.output.equals("NaN")) {
- if (!Double.isNaN(actual.doubleValue())) {
- return "Expected NaN, but got: " + actual;
- }
- return null;
- } else if (tuple.output.equals("Inf")) {
- if (!Double.isInfinite(actual.doubleValue())
- || Double.compare(actual.doubleValue(), 0.0) < 0) {
- return "Expected Inf, but got: " + actual;
- }
- return null;
- } else if (tuple.output.equals("-Inf")) {
- if (!Double.isInfinite(actual.doubleValue())
- || Double.compare(actual.doubleValue(), 0.0) > 0) {
- return "Expected -Inf, but got: " + actual;
- }
- return null;
- } else if (tuple.output.equals("fail")) {
- return null;
- } else if (new BigDecimal(tuple.output).compareTo(new BigDecimal(actual.toString()))
- != 0) {
- return "Expected: " + tuple.output + ", got: " + actual;
- } else {
- return null;
- }
- }
-
- /**
- * Runs a single parse currency test. On success, returns null. On failure, returns the
- * error. This implementation just returns null. Subclasses should override.
- *
- * @param tuple contains the parameters of the format test.
- */
- @Override
- public String parseCurrency(DataDrivenNumberFormatTestData tuple) {
- String pattern = (tuple.pattern == null) ? "0" : tuple.pattern;
- Properties properties;
- ParsePosition ppos = new ParsePosition(0);
- CurrencyAmount actual;
- try {
- properties =
- PatternString.parseToProperties(
- pattern,
- tuple.currency != null
- ? PatternString.IGNORE_ROUNDING_ALWAYS
- : PatternString.IGNORE_ROUNDING_NEVER);
- propertiesFromTuple(tuple, properties);
- actual =
- Parse.parseCurrency(
- tuple.parse, ppos, properties, DecimalFormatSymbols.getInstance(tuple.locale));
- } catch (ParseException e) {
- e.printStackTrace();
- return "parse exception: " + e.getMessage();
- }
- if (ppos.getIndex() == 0 || actual.getCurrency().getCurrencyCode().equals("XXX")) {
- return "Parse failed; got " + actual + ", but expected " + tuple.output;
- }
- BigDecimal expectedNumber = new BigDecimal(tuple.output);
- if (expectedNumber.compareTo(new BigDecimal(actual.getNumber().toString())) != 0) {
- return "Wrong number: Expected: " + expectedNumber + ", got: " + actual;
- }
- String expectedCurrency = tuple.outputCurrency;
- if (!expectedCurrency.equals(actual.getCurrency().toString())) {
- return "Wrong currency: Expected: " + expectedCurrency + ", got: " + actual;
- }
- return null;
- }
-
- /**
- * Runs a single select test. On success, returns null. On failure, returns the error. This
- * implementation just returns null. Subclasses should override.
- *
- * @param tuple contains the parameters of the format test.
- */
- @Override
- public String select(DataDrivenNumberFormatTestData tuple) {
- return null;
- }
- };
-
static void propertiesFromTuple(DataDrivenNumberFormatTestData tuple, Properties properties) {
if (tuple.minIntegerDigits != null) {
properties.setMinimumIntegerDigits(tuple.minIntegerDigits);
}
if (tuple.useScientific != null) {
properties.setMinimumExponentDigits(
- tuple.useScientific != 0 ? 1 : Properties.DEFAULT_MINIMUM_EXPONENT_DIGITS);
+ tuple.useScientific != 0 ? 1 : -1);
}
if (tuple.grouping != null) {
properties.setGroupingSize(tuple.grouping);
"numberformattestspecification.txt", JDK);
}
- @Test
- public void TestDataDrivenICU59() {
- DataDrivenNumberFormatTestUtility.runFormatSuiteIncludingKnownFailures(
- "numberformattestspecification.txt", ICU59);
- }
-
@Test
public void TestDataDrivenICU60() {
DataDrivenNumberFormatTestUtility.runFormatSuiteIncludingKnownFailures(
{"#0#@#*#;#", false, 9, "#0#@#*#;#"}
};
- // ar_SA has an interesting percent sign and various Arabic letter marks
- DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(new ULocale("ar_SA"));
- NumberStringBuilder sb = new NumberStringBuilder();
-
for (Object[] cas : cases) {
String input = (String) cas[0];
boolean curr = (Boolean) cas[1];
"Currency on <" + input + ">", curr, AffixPatternUtils.hasCurrencySymbols(input));
assertEquals("Length on <" + input + ">", length, AffixPatternUtils.unescapedLength(input));
- sb.clear();
- AffixPatternUtils.unescape(input, symbols, "$", "XXX", "long name", "−", sb);
- assertEquals("Output on <" + input + ">", output, sb.toString());
+ String actual = unescapeWithDefaults(input);
+ assertEquals("Output on <" + input + ">", output, actual);
}
}
@Test
public void testInvalid() {
String[] invalidExamples = {"'", "x'", "'x", "'x''", "''x'"};
- DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(new ULocale("en_US"));
- NumberStringBuilder sb = new NumberStringBuilder();
for (String str : invalidExamples) {
try {
// OK
}
try {
- AffixPatternUtils.unescape(str, symbols, "$", "XXX", "long name", "−", sb);
+ unescapeWithDefaults(str);
fail("No exception was thrown on an invalid string");
} catch (IllegalArgumentException e) {
// OK
AffixPatternUtils.unescape("-+%", sb, 4, provider);
assertEquals("Symbol provider into middle", "abcd123efg", sb.toString());
}
+
+ private static final SymbolProvider DEFAULT_SYMBOL_PROVIDER =
+ new SymbolProvider() {
+ // ar_SA has an interesting percent sign and various Arabic letter marks
+ private final DecimalFormatSymbols SYMBOLS =
+ DecimalFormatSymbols.getInstance(new ULocale("ar_SA"));
+
+ @Override
+ public CharSequence getSymbol(int type) {
+ switch (type) {
+ case AffixPatternUtils.TYPE_MINUS_SIGN:
+ return "−";
+ case AffixPatternUtils.TYPE_PLUS_SIGN:
+ return SYMBOLS.getPlusSignString();
+ case AffixPatternUtils.TYPE_PERCENT:
+ return SYMBOLS.getPercentString();
+ case AffixPatternUtils.TYPE_PERMILLE:
+ return SYMBOLS.getPerMillString();
+ case AffixPatternUtils.TYPE_CURRENCY_SINGLE:
+ return "$";
+ case AffixPatternUtils.TYPE_CURRENCY_DOUBLE:
+ return "XXX";
+ case AffixPatternUtils.TYPE_CURRENCY_TRIPLE:
+ return "long name";
+ case AffixPatternUtils.TYPE_CURRENCY_QUAD:
+ return "\uFFFD";
+ case AffixPatternUtils.TYPE_CURRENCY_QUINT:
+ // TODO: Add support for narrow currency symbols here.
+ return "\uFFFD";
+ case AffixPatternUtils.TYPE_CURRENCY_OVERFLOW:
+ return "\uFFFD";
+ default:
+ throw new AssertionError();
+ }
+ }
+ };
+
+ private static String unescapeWithDefaults(String input) {
+ NumberStringBuilder nsb = new NumberStringBuilder();
+ AffixPatternUtils.unescape(input, nsb, 0, DEFAULT_SYMBOL_PROVIDER);
+ return nsb.toString();
+ }
}
import org.junit.Test;
import com.ibm.icu.dev.test.TestFmwk;
-import com.ibm.icu.impl.number.Endpoint;
-import com.ibm.icu.impl.number.Format;
import com.ibm.icu.impl.number.FormatQuantity;
import com.ibm.icu.impl.number.FormatQuantity1;
import com.ibm.icu.impl.number.FormatQuantity2;
import com.ibm.icu.impl.number.FormatQuantity4;
import com.ibm.icu.impl.number.Properties;
import com.ibm.icu.text.CompactDecimalFormat.CompactStyle;
+import com.ibm.icu.util.ULocale;
+
+import newapi.impl.NumberFormatterImpl;
+import newapi.impl.NumberPropertyMapper;
/** TODO: This is a temporary name for this class. Suggestions for a better name? */
public class FormatQuantityTest extends TestFmwk {
public void testBehavior() throws ParseException {
// Make a list of several formatters to test the behavior of FormatQuantity.
- List<Format> formats = new ArrayList<Format>();
+ List<NumberFormatterImpl> formats = new ArrayList<NumberFormatterImpl>();
Properties properties = new Properties();
- Format ndf = Endpoint.fromBTA(properties);
- formats.add(ndf);
+ formats.add(NumberPropertyMapper.create(properties, null, ULocale.ENGLISH));
properties =
new Properties()
.setMinimumSignificantDigits(3)
.setMaximumSignificantDigits(3)
.setCompactStyle(CompactStyle.LONG);
- Format cdf = Endpoint.fromBTA(properties);
- formats.add(cdf);
+ formats.add(NumberPropertyMapper.create(properties, null, ULocale.ENGLISH));
properties =
new Properties()
.setMinimumExponentDigits(1)
.setMaximumIntegerDigits(3)
.setMaximumFractionDigits(1);
- Format exf = Endpoint.fromBTA(properties);
- formats.add(exf);
+ formats.add(NumberPropertyMapper.create(properties, null, ULocale.ENGLISH));
properties = new Properties().setRoundingIncrement(new BigDecimal("0.5"));
- Format rif = Endpoint.fromBTA(properties);
- formats.add(rif);
+ formats.add(NumberPropertyMapper.create(properties, null, ULocale.ENGLISH));
String[] cases = {
"1.0",
}
}
- static void testFormatQuantity(int t, String str, List<Format> formats, int mode) {
+ static void testFormatQuantity(int t, String str, List<NumberFormatterImpl> formats, int mode) {
if (mode == 2) {
assertEquals("Double is not valid", Double.toString(Double.parseDouble(str)), str);
}
}
private static void testFormatQuantityWithFormats(
- FormatQuantity rq0, FormatQuantity rq1, List<Format> formats) {
- for (Format format : formats) {
+ FormatQuantity rq0, FormatQuantity rq1, List<NumberFormatterImpl> formats) {
+ for (NumberFormatterImpl format : formats) {
FormatQuantity q0 = rq0.createCopy();
FormatQuantity q1 = rq1.createCopy();
- String s1 = format.format(q0);
- String s2 = format.format(q1);
+ String s1 = format.format(q0).toString();
+ String s2 = format.format(q1).toString();
assertEquals("Different output from formatter (" + q0 + ", " + q1 + ")", s1, s2);
}
}
import org.junit.Ignore;
import org.junit.Test;
-import com.ibm.icu.impl.number.formatters.PaddingFormat.PadPosition;
+import com.ibm.icu.impl.number.ThingsNeedingNewHome.PadPosition;
import com.ibm.icu.text.DecimalFormatSymbols;
import com.ibm.icu.text.MeasureFormat.FormatWidth;
import com.ibm.icu.text.NumberingSystem;
import com.ibm.icu.impl.number.Parse.ParseMode;
import com.ibm.icu.impl.number.PatternString;
import com.ibm.icu.impl.number.Properties;
-import com.ibm.icu.impl.number.formatters.CurrencyFormat.CurrencyStyle;
-import com.ibm.icu.impl.number.formatters.PaddingFormat.PadPosition;
+import com.ibm.icu.impl.number.ThingsNeedingNewHome.PadPosition;
import com.ibm.icu.text.CompactDecimalFormat.CompactStyle;
import com.ibm.icu.text.CurrencyPluralInfo;
import com.ibm.icu.text.MeasureFormat.FormatWidth;
ULocale[] locales = ULocale.getAvailableLocales();
return CurrencyPluralInfo.getInstance(locales[seed % locales.length]);
- } else if (type == CurrencyStyle.class) {
- if (seed == 0) return null;
- CurrencyStyle[] values = CurrencyStyle.values();
- return values[seed % values.length];
-
} else if (type == CurrencyUsage.class) {
if (seed == 0) return null;
CurrencyUsage[] values = CurrencyUsage.values();