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.
PositiveNegativeAffixFormat.IProperties properties) {
// Use a different code path for handling affixes with "always show plus sign"
- if (properties.getPlusSignAlwaysShown()) {
+ if (properties.getSignAlwaysShown()) {
return getModifiersWithPlusSign(symbols, curr1, curr2, curr3, properties);
}
private void setPositiveResult(
NumberStringBuilder prefix, NumberStringBuilder suffix, IProperties properties) {
- if (properties.getPositivePrefix() != null || properties.getPositiveSuffix() != null) {
- // Override with custom affixes
- String _prefix = properties.getPositivePrefix();
- String _suffix = properties.getPositiveSuffix();
- if (_prefix == null) _prefix = "";
- if (_suffix == null) _suffix = "";
- if (_prefix.length() == 0 && _suffix.length() == 0) {
- resultInstance.positive = ConstantAffixModifier.EMPTY;
- return;
- }
- if (resultInstance.positive != null
- && (resultInstance.positive instanceof ConstantAffixModifier)
- && ((ConstantAffixModifier) resultInstance.positive).contentEquals(_prefix, _suffix)) {
- // Use the cached modifier
- return;
- }
- resultInstance.positive =
- new ConstantAffixModifier(_prefix, _suffix, null, false);
- } else {
- // Use pattern affixes
- 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);
+ // 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) {
- if (properties.getNegativePrefix() != null || properties.getNegativeSuffix() != null) {
- // Override with custom affixes
- String _prefix = properties.getNegativePrefix();
- String _suffix = properties.getNegativeSuffix();
- if (_prefix == null) _prefix = "";
- if (_suffix == null) _suffix = "";
- if (_prefix.length() == 0 && _suffix.length() == 0) {
- resultInstance.negative = ConstantAffixModifier.EMPTY;
- return;
- }
- if (resultInstance.negative != null
- && (resultInstance.negative instanceof ConstantAffixModifier)
- && ((ConstantAffixModifier) resultInstance.negative).contentEquals(_prefix, _suffix)) {
- // Use the cached modifier
- return;
- }
- resultInstance.negative =
- new ConstantAffixModifier(_prefix, _suffix, null, false);
- } else {
- // Use pattern affixes
- 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);
+ 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. */
AffixHolder ps = fromPropertiesPositiveString(properties);
AffixHolder ns = fromPropertiesNegativeString(properties);
if (pp == null && ps == null) {
- if (properties.getPlusSignAlwaysShown()) {
+ if (properties.getSignAlwaysShown()) {
state.affixHolders.add(DEFAULT_POSITIVE);
} else {
state.affixHolders.add(EMPTY_POSITIVE);
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.rounders.SignificantDigitsRounder.SignificantDigitsMode;
import com.ibm.icu.text.CompactDecimalFormat.CompactStyle;
import com.ibm.icu.text.CurrencyPluralInfo;
+import com.ibm.icu.text.DecimalFormat.SignificantDigitsMode;
import com.ibm.icu.text.MeasureFormat.FormatWidth;
import com.ibm.icu.util.Currency;
import com.ibm.icu.util.Currency.CurrencyUsage;
private transient boolean parseIntegerOnly;
private transient ParseMode parseMode;
private transient boolean parseToBigDecimal;
- private transient boolean plusSignAlwaysShown;
private transient String positivePrefix;
private transient String positivePrefixPattern;
private transient String positiveSuffix;
private transient BigDecimal roundingIncrement;
private transient RoundingMode roundingMode;
private transient int secondaryGroupingSize;
+ private transient boolean signAlwaysShown;
private transient SignificantDigitsMode significantDigitsMode;
/*--------------------------------------------------------------------------------------------+/
parseMode = DEFAULT_PARSE_MODE;
parseNoExponent = DEFAULT_PARSE_NO_EXPONENT;
parseToBigDecimal = DEFAULT_PARSE_TO_BIG_DECIMAL;
- plusSignAlwaysShown = DEFAULT_PLUS_SIGN_ALWAYS_SHOWN;
positivePrefix = DEFAULT_POSITIVE_PREFIX;
positivePrefixPattern = DEFAULT_POSITIVE_PREFIX_PATTERN;
positiveSuffix = DEFAULT_POSITIVE_SUFFIX;
roundingIncrement = DEFAULT_ROUNDING_INCREMENT;
roundingMode = DEFAULT_ROUNDING_MODE;
secondaryGroupingSize = DEFAULT_SECONDARY_GROUPING_SIZE;
+ signAlwaysShown = DEFAULT_SIGN_ALWAYS_SHOWN;
significantDigitsMode = DEFAULT_SIGNIFICANT_DIGITS_MODE;
return this;
}
parseMode = other.parseMode;
parseNoExponent = other.parseNoExponent;
parseToBigDecimal = other.parseToBigDecimal;
- plusSignAlwaysShown = other.plusSignAlwaysShown;
positivePrefix = other.positivePrefix;
positivePrefixPattern = other.positivePrefixPattern;
positiveSuffix = other.positiveSuffix;
roundingIncrement = other.roundingIncrement;
roundingMode = other.roundingMode;
secondaryGroupingSize = other.secondaryGroupingSize;
+ signAlwaysShown = other.signAlwaysShown;
significantDigitsMode = other.significantDigitsMode;
return this;
}
eq = eq && _equalsHelper(parseMode, other.parseMode);
eq = eq && _equalsHelper(parseNoExponent, other.parseNoExponent);
eq = eq && _equalsHelper(parseToBigDecimal, other.parseToBigDecimal);
- eq = eq && _equalsHelper(plusSignAlwaysShown, other.plusSignAlwaysShown);
eq = eq && _equalsHelper(positivePrefix, other.positivePrefix);
eq = eq && _equalsHelper(positivePrefixPattern, other.positivePrefixPattern);
eq = eq && _equalsHelper(positiveSuffix, other.positiveSuffix);
eq = eq && _equalsHelper(roundingIncrement, other.roundingIncrement);
eq = eq && _equalsHelper(roundingMode, other.roundingMode);
eq = eq && _equalsHelper(secondaryGroupingSize, other.secondaryGroupingSize);
+ eq = eq && _equalsHelper(signAlwaysShown, other.signAlwaysShown);
eq = eq && _equalsHelper(significantDigitsMode, other.significantDigitsMode);
return eq;
}
hashCode ^= _hashCodeHelper(parseMode);
hashCode ^= _hashCodeHelper(parseNoExponent);
hashCode ^= _hashCodeHelper(parseToBigDecimal);
- hashCode ^= _hashCodeHelper(plusSignAlwaysShown);
hashCode ^= _hashCodeHelper(positivePrefix);
hashCode ^= _hashCodeHelper(positivePrefixPattern);
hashCode ^= _hashCodeHelper(positiveSuffix);
hashCode ^= _hashCodeHelper(roundingIncrement);
hashCode ^= _hashCodeHelper(roundingMode);
hashCode ^= _hashCodeHelper(secondaryGroupingSize);
+ hashCode ^= _hashCodeHelper(signAlwaysShown);
hashCode ^= _hashCodeHelper(significantDigitsMode);
return hashCode;
}
}
@Override
- public boolean getPlusSignAlwaysShown() {
- return plusSignAlwaysShown;
+ public boolean getSignAlwaysShown() {
+ return signAlwaysShown;
}
@Override
}
@Override
- public Properties setPlusSignAlwaysShown(boolean plusSignAlwaysShown) {
- this.plusSignAlwaysShown = plusSignAlwaysShown;
+ public Properties setSignAlwaysShown(boolean signAlwaysShown) {
+ this.signAlwaysShown = signAlwaysShown;
return this;
}
*/
public IProperties setNegativeSuffixPattern(String negativeSuffixPattern);
- static boolean DEFAULT_PLUS_SIGN_ALWAYS_SHOWN = false;
+ static boolean DEFAULT_SIGN_ALWAYS_SHOWN = false;
- /** @see #setPlusSignAlwaysShown */
- public boolean getPlusSignAlwaysShown();
+ /** @see #setSignAlwaysShown */
+ public boolean getSignAlwaysShown();
/**
* Sets whether to always display of a plus sign on positive numbers.
* @param plusSignAlwaysShown Whether positive numbers should display a plus sign.
* @return The property bag, for chaining.
*/
- public IProperties setPlusSignAlwaysShown(boolean plusSignAlwaysShown);
+ public IProperties setSignAlwaysShown(boolean plusSignAlwaysShown);
}
public static PositiveNegativeAffixModifier getInstance(DecimalFormatSymbols symbols, IProperties properties) {
import com.ibm.icu.impl.number.FormatQuantity;
import com.ibm.icu.impl.number.Properties;
import com.ibm.icu.impl.number.Rounder;
+import com.ibm.icu.text.DecimalFormat.SignificantDigitsMode;
public class SignificantDigitsRounder extends Rounder {
- public static enum SignificantDigitsMode {
- OVERRIDE_MAXIMUM_FRACTION,
- RESPECT_MAXIMUM_FRACTION,
- ENSURE_MINIMUM_SIGNIFICANT
- };
-
public static interface IProperties extends Rounder.IBasicRoundingProperties {
static int DEFAULT_MINIMUM_SIGNIFICANT_DIGITS = -1;
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.rounders.SignificantDigitsRounder.SignificantDigitsMode;
import com.ibm.icu.lang.UCharacter;
import com.ibm.icu.math.BigDecimal;
import com.ibm.icu.math.MathContext;
refreshFormatter();
}
+ /**
+ * @return Whether the sign is being shown on positive numbers.
+ * @see #setSignAlwaysShown
+ * @category Affixes
+ * @internal
+ * @deprecated This API is technical preview.
+ */
+ @Deprecated
+ public synchronized boolean getSignAlwaysShown() {
+ // This is not in the exported properties
+ return properties.getSignAlwaysShown();
+ }
+
+ /**
+ * Sets whether to always shown the plus sign ('+' in <em>en</em>) on positive numbers. The rules
+ * in UTS #35 section 3.2.1 will be followed to ensure a locale-aware placement of the sign.
+ *
+ * @param value true to always show a sign; false to hide the sign on positive numbers.
+ * @category Affixes
+ * @internal
+ * @deprecated ICU 59: This API is technical preview. It may change in an upcoming release.
+ */
+ @Deprecated
+ public synchronized void setSignAlwaysShown(boolean value) {
+ properties.setSignAlwaysShown(value);
+ refreshFormatter();
+ }
+
/**
* @return The multiplier being applied to numbers before they are formatted.
* @see #setMultiplier
public void set(Properties props);
}
+ /**
+ * An enum containing the choices for significant digits modes.
+ *
+ * @see #setSignificantDigitsMode
+ * @internal
+ * @deprecated ICU 59: This API is technical preview. It may change in an upcoming release.
+ */
+ @Deprecated
+ public static enum SignificantDigitsMode {
+ /**
+ * Respect significant digits counts, ignoring the fraction length.
+ *
+ * @see #setSignificantDigitsMode
+ * @internal
+ * @deprecated ICU 59: This API is technical preview. It may change in an upcoming release.
+ */
+ @Deprecated
+ OVERRIDE_MAXIMUM_FRACTION,
+
+ /**
+ * Respect the fraction length, overriding significant digits counts if necessary.
+ *
+ * @see #setSignificantDigitsMode
+ * @internal
+ * @deprecated ICU 59: This API is technical preview. It may change in an upcoming release.
+ */
+ @Deprecated
+ RESPECT_MAXIMUM_FRACTION,
+
+ /**
+ * Respect minimum significant digits, overriding fraction length if necessary.
+ *
+ * @see #setSignificantDigitsMode
+ * @internal
+ * @deprecated ICU 59: This API is technical preview. It may change in an upcoming release.
+ */
+ @Deprecated
+ ENSURE_MINIMUM_SIGNIFICANT
+ }
+
/**
* {@icu} Constant for {@link #getPadPosition()} and {@link #setPadPosition(int)} to specify pad
* characters inserted before the prefix.
assertEquals("Should not display any extra fraction digits", "70K", actual);
}
+ @Test
+ public void TestLocaleGroupingForLargeNumbers() {
+ ULocale[] locs = {new ULocale("en"), new ULocale("it"), new ULocale("en_US_POSIX"), new ULocale("en-IN")};
+ String[] expecteds = {"5,800,000T", "5.800.000 Bln", "5800000T", "58,00,000T"};
+ for (int i=0; i<locs.length; i++) {
+ ULocale loc = locs[i];
+ String exp = expecteds[i];
+ CompactDecimalFormat cdf = CompactDecimalFormat.getInstance(loc, CompactStyle.SHORT);
+ String act = cdf.format(5.8e18);
+ assertEquals("Grouping sizes for very large numbers: " + loc, exp, act);
+ }
+ }
+
@Test
public void TestBug12422() {
CompactDecimalFormat cdf;
import com.ibm.icu.impl.LocaleUtility;
import com.ibm.icu.impl.data.ResourceReader;
import com.ibm.icu.impl.data.TokenIterator;
-import com.ibm.icu.impl.number.rounders.SignificantDigitsRounder.SignificantDigitsMode;
import com.ibm.icu.math.BigDecimal;
import com.ibm.icu.math.MathContext;
import com.ibm.icu.text.CompactDecimalFormat;
import com.ibm.icu.text.DecimalFormat;
+import com.ibm.icu.text.DecimalFormat.SignificantDigitsMode;
import com.ibm.icu.text.DecimalFormatSymbols;
import com.ibm.icu.text.DisplayContext;
import com.ibm.icu.text.MeasureFormat;
df.setPositiveSuffix("0K");
df.setNegativeSuffix("0N");
expect2(df, 123, "1230K");
- expect2(df, -123, "1230N");
+ expect2(df, -123, "-1230N");
}
@Test
assertEquals("Should parse 12 and -5", 7, n1.intValue() + n2.intValue());
}
+ @Test
+ public void testSetPrefixDefaultSuffix() {
+ DecimalFormat df = (DecimalFormat) NumberFormat.getPercentInstance();
+ df.setPositivePrefix("+");
+ assertEquals("Should have manual plus sign and auto percent sign", "+100%", df.format(1));
+ }
+
@Test
public void testMultiCodePointPaddingInPattern() {
DecimalFormat df = new DecimalFormat("a*'நி'###0b");
}
}
}
+
+ @Test
+ public void testPlusSignAlwaysShown() {
+ double[] numbers = {0.012, 5.78, 0, -0.012, -5.78};
+ ULocale[] locs = {new ULocale("en-US"), new ULocale("ar-EG"), new ULocale("es-CL")};
+ String[][][] expecteds = {
+ // en-US
+ {
+ // decimal
+ { "+0.012", "+5.78", "+0", "-0.012", "-5.78" },
+ // currency
+ { "+$0.01", "+$5.78", "+$0.00", "-$0.01", "-$5.78" }
+ },
+ // ar-EG (interesting because the plus sign string starts with \u061C)
+ {
+ // decimal
+ {
+ "\u061C+\u0660\u066B\u0660\u0661\u0662", // "+٠٫٠١٢"
+ "\u061C+\u0665\u066B\u0667\u0668", // "+٥٫٧٨"
+ "\u061C+\u0660", // "+٠"
+ "\u061C-\u0660\u066B\u0660\u0661\u0662", // "-٠٫٠١٢"
+ "\u061C-\u0665\u066B\u0667\u0668", // "-٥٫٧٨"
+ },
+ // currency (\062C.\0645.\200F is the currency sign in ar for EGP)
+ {
+ "\u061C+\u0660\u066B\u0660\u0661\u00A0\u062C.\u0645.\u200F",
+ "\u061C+\u0665\u066B\u0667\u0668\u00A0\u062C.\u0645.\u200F",
+ "\u061C+\u0660\u066B\u0660\u0660\u00A0\u062C.\u0645.\u200F",
+ "\u061C-\u0660\u066B\u0660\u0661\u00A0\u062C.\u0645.\u200F",
+ "\u061C-\u0665\u066B\u0667\u0668\u00A0\u062C.\u0645.\u200F"
+ }
+ },
+ // es-CL (interesting because of position of sign in currency)
+ {
+ // decimal
+ { "+0,012", "+5,78", "+0", "-0,012", "-5,78" },
+ // currency (note: rounding for es-CL's currency, CLP, is 0 fraction digits)
+ { "$+0", "$+6", "$+0", "$-0", "$-6" }
+ }
+ };
+
+ for (int i=0; i<locs.length; i++) {
+ ULocale loc = locs[i];
+ DecimalFormat df1 = (DecimalFormat) NumberFormat.getNumberInstance(loc);
+ assertFalse("Default should be false", df1.getSignAlwaysShown());
+ df1.setSignAlwaysShown(true);
+ assertTrue("Getter should now return true", df1.getSignAlwaysShown());
+ DecimalFormat df2 = (DecimalFormat) NumberFormat.getCurrencyInstance(loc);
+ assertFalse("Default should be false", df2.getSignAlwaysShown());
+ df2.setSignAlwaysShown(true);
+ assertTrue("Getter should now return true", df2.getSignAlwaysShown());
+ for (int j=0; j<2; j++) {
+ DecimalFormat df = (j == 0) ? df1 : df2;
+ for (int k=0; k<numbers.length; k++) {
+ double d = numbers[k];
+ String exp = expecteds[i][j][k];
+ String act = df.format(d);
+ assertEquals("Locale " + loc + ", type " + j + ", " + d, exp, act);
+ }
+ }
+ }
+ }
}
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.rounders.SignificantDigitsRounder.SignificantDigitsMode;
import com.ibm.icu.text.CompactDecimalFormat.CompactStyle;
import com.ibm.icu.text.CurrencyPluralInfo;
+import com.ibm.icu.text.DecimalFormat.SignificantDigitsMode;
import com.ibm.icu.text.MeasureFormat.FormatWidth;
import com.ibm.icu.util.Currency;
import com.ibm.icu.util.Currency.CurrencyUsage;
import com.ibm.icu.impl.number.FormatQuantity4;
import com.ibm.icu.impl.number.Properties;
import com.ibm.icu.impl.number.rounders.SignificantDigitsRounder;
-import com.ibm.icu.impl.number.rounders.SignificantDigitsRounder.SignificantDigitsMode;
+import com.ibm.icu.text.DecimalFormat.SignificantDigitsMode;
public class RounderTest {