import java.util.Objects;
-import com.ibm.icu.number.NumberFormatterSettings;
import com.ibm.icu.number.NumberRangeFormatter.RangeCollapse;
import com.ibm.icu.number.NumberRangeFormatter.RangeIdentityFallback;
+import com.ibm.icu.number.UnlocalizedNumberFormatter;
import com.ibm.icu.util.ULocale;
/**
*
*/
public class RangeMacroProps {
- public NumberFormatterSettings<?> formatter1;
- public NumberFormatterSettings<?> formatter2;
+ public UnlocalizedNumberFormatter formatter1;
+ public UnlocalizedNumberFormatter formatter2;
public RangeCollapse collapse;
public RangeIdentityFallback identityFallback;
public ULocale loc;
import com.ibm.icu.impl.number.DecimalQuantity;
import com.ibm.icu.impl.number.DecimalQuantity_DualStorageBCD;
import com.ibm.icu.impl.number.NumberStringBuilder;
+import com.ibm.icu.impl.number.range.RangeMacroProps;
import com.ibm.icu.number.FormattedNumberRange.RangeIdentityType;
-import com.ibm.icu.text.NumberFormat;
/**
* A NumberRangeFormatter that has a locale associated with it; this means .formatRange() methods are available.
* @see NumberRangeFormatter
*/
public FormattedNumberRange formatRange(int first, int second) {
- // TODO: This is a placeholder implementation.
DecimalQuantity dq1 = new DecimalQuantity_DualStorageBCD(first);
DecimalQuantity dq2 = new DecimalQuantity_DualStorageBCD(second);
+ return formatImpl(dq1, dq2);
+ }
+
+ /**
+ * Format the given doubles to a string using the settings specified in the NumberRangeFormatter fluent setting
+ * chain.
+ *
+ * @param first
+ * The first number in the range, usually to the left in LTR locales.
+ * @param second
+ * The second number in the range, usually to the right in LTR locales.
+ * @return A FormattedNumber object; call .toString() to get the string.
+ * @draft ICU 63
+ * @provisional This API might change or be removed in a future release.
+ * @see NumberRangeFormatter
+ */
+ public FormattedNumberRange formatRange(double first, double second) {
+ DecimalQuantity dq1 = new DecimalQuantity_DualStorageBCD(first);
+ DecimalQuantity dq2 = new DecimalQuantity_DualStorageBCD(second);
+ return formatImpl(dq1, dq2);
+ }
+
+ /**
+ * Format the given Numbers to a string using the settings specified in the NumberRangeFormatter fluent setting
+ * chain.
+ *
+ * @param first
+ * The first number in the range, usually to the left in LTR locales.
+ * @param second
+ * The second number in the range, usually to the right in LTR locales.
+ * @return A FormattedNumber object; call .toString() to get the string.
+ * @draft ICU 63
+ * @provisional This API might change or be removed in a future release.
+ * @see NumberRangeFormatter
+ */
+ public FormattedNumberRange formatRange(Number first, Number second) {
+ DecimalQuantity dq1 = new DecimalQuantity_DualStorageBCD(first);
+ DecimalQuantity dq2 = new DecimalQuantity_DualStorageBCD(second);
+ return formatImpl(dq1, dq2);
+ }
+
+ FormattedNumberRange formatImpl(DecimalQuantity first, DecimalQuantity second) {
+ // TODO: This is a placeholder implementation.
+ RangeMacroProps macros = resolve();
+ LocalizedNumberFormatter f1 , f2;
+ if (macros.formatter1 != null) {
+ f1 = macros.formatter1.locale(macros.loc);
+ } else {
+ f1 = NumberFormatter.withLocale(macros.loc);
+ }
+ if (macros.formatter2 != null) {
+ f2 = macros.formatter2.locale(macros.loc);
+ } else {
+ f2 = NumberFormatter.withLocale(macros.loc);
+ }
+ FormattedNumber r1 = f1.format(first);
+ FormattedNumber r2 = f2.format(second);
NumberStringBuilder nsb = new NumberStringBuilder();
- nsb.append(dq1.toPlainString(), NumberFormat.Field.INTEGER);
+ nsb.append(r1.nsb);
nsb.append(" --- ", null);
- nsb.append(dq2.toPlainString(), NumberFormat.Field.INTEGER);
+ nsb.append(r2.nsb);
RangeIdentityType identityType = (first == second) ? RangeIdentityType.EQUAL_BEFORE_ROUNDING
: RangeIdentityType.NOT_EQUAL;
- return new FormattedNumberRange(nsb, dq1, dq2, identityType);
+ return new FormattedNumberRange(nsb, first, second, identityType);
}
@Override
// License & terms of use: http://www.unicode.org/copyright.html#License
package com.ibm.icu.number;
+import java.util.Locale;
+
+import com.ibm.icu.util.ULocale;
+
/**
* The main entrypoint to the formatting of ranges of numbers, including currencies and other units of measurement.
*
public static enum RangeIdentityFallback {}
+ private static final UnlocalizedNumberRangeFormatter BASE = new UnlocalizedNumberRangeFormatter();
+
+ public static UnlocalizedNumberRangeFormatter with() {
+ return BASE;
+ }
+
+ public static LocalizedNumberRangeFormatter withLocale(Locale locale) {
+ return BASE.locale(locale);
+ }
+
+ public static LocalizedNumberRangeFormatter withLocale(ULocale locale) {
+ return BASE.locale(locale);
+ }
+
}
this.value = value;
}
- public T numberFormatter(NumberFormatterSettings<?> formatter) {
+ public T numberFormatter(UnlocalizedNumberFormatter formatter) {
return numberFormatters(formatter, formatter);
}
- public T numberFormatters(NumberFormatterSettings<?> formatterFirst, NumberFormatterSettings<?> formatterSecond) {
+ public T numberFormatters(UnlocalizedNumberFormatter formatterFirst, UnlocalizedNumberFormatter formatterSecond) {
T intermediate = create(KEY_FORMATTER_1, formatterFirst);
return (T) intermediate.create(KEY_FORMATTER_2, formatterSecond);
}
break;
case KEY_FORMATTER_1:
if (macros.formatter1 == null) {
- macros.formatter1 = (NumberFormatterSettings<?>) current.value;
+ macros.formatter1 = (UnlocalizedNumberFormatter) current.value;
}
break;
case KEY_FORMATTER_2:
if (macros.formatter2 == null) {
- macros.formatter2 = (NumberFormatterSettings<?>) current.value;
+ macros.formatter2 = (UnlocalizedNumberFormatter) current.value;
}
break;
case KEY_COLLAPSE:
if (other == null) {
return false;
}
- if (!(other instanceof NumberFormatterSettings)) {
+ if (!(other instanceof NumberRangeFormatterSettings)) {
return false;
}
- return resolve().equals(((NumberFormatterSettings<?>) other).resolve());
+ return resolve().equals(((NumberRangeFormatterSettings<?>) other).resolve());
}
}
--- /dev/null
+// © 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html#License
+package com.ibm.icu.dev.test.number;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Locale;
+
+import org.junit.Test;
+
+import com.ibm.icu.number.LocalizedNumberRangeFormatter;
+import com.ibm.icu.number.NumberFormatter;
+import com.ibm.icu.number.NumberFormatter.GroupingStrategy;
+import com.ibm.icu.number.NumberRangeFormatter;
+import com.ibm.icu.number.UnlocalizedNumberRangeFormatter;
+import com.ibm.icu.util.Currency;
+import com.ibm.icu.util.ULocale;
+
+/**
+ * @author sffc
+ *
+ */
+public class NumberRangeFormatterTest {
+
+ private static final Currency USD = Currency.getInstance("USD");
+ private static final Currency GBP = Currency.getInstance("GBP");
+
+ @Test
+ public void testSanity() {
+ LocalizedNumberRangeFormatter lnrf1 = NumberRangeFormatter.withLocale(ULocale.US);
+ LocalizedNumberRangeFormatter lnrf2 = NumberRangeFormatter.with().locale(ULocale.US);
+ LocalizedNumberRangeFormatter lnrf3 = NumberRangeFormatter.withLocale(Locale.US);
+ LocalizedNumberRangeFormatter lnrf4 = NumberRangeFormatter.with().locale(Locale.US);
+ assertEquals("Formatters should be equal 1", lnrf1, lnrf2);
+ assertEquals("Formatters should be equal 2", lnrf2, lnrf3);
+ assertEquals("Formatters should be equal 3", lnrf3, lnrf4);
+ assertEquals("Formatters should have same behavior 1", lnrf1.formatRange(4, 6), lnrf2.formatRange(4, 6));
+ assertEquals("Formatters should have same behavior 2", lnrf2.formatRange(4, 6), lnrf3.formatRange(4, 6));
+ assertEquals("Formatters should have same behavior 3", lnrf3.formatRange(4, 6), lnrf4.formatRange(4, 6));
+ }
+
+ @Test
+ public void testBasic() {
+ assertFormatRange(
+ "Basic",
+ NumberRangeFormatter.with(),
+ ULocale.US,
+ "1 --- 5",
+ "5 --- 5",
+ "5 --- 5",
+ "0 --- 3",
+ "0 --- 0",
+ "3 --- 3,000",
+ "3,000 --- 5,000",
+ "4,999 --- 5,001",
+ "5,000 --- 5,000",
+ "5,000 --- 5,000,000");
+ }
+
+ @Test
+ public void testNullBehavior() {
+ assertFormatRange(
+ "Basic",
+ NumberRangeFormatter.with().numberFormatter(null),
+ ULocale.US,
+ "1 --- 5",
+ "5 --- 5",
+ "5 --- 5",
+ "0 --- 3",
+ "0 --- 0",
+ "3 --- 3,000",
+ "3,000 --- 5,000",
+ "4,999 --- 5,001",
+ "5,000 --- 5,000",
+ "5,000 --- 5,000,000");
+
+ assertFormatRange(
+ "Basic",
+ NumberRangeFormatter.with().numberFormatters(null, null),
+ ULocale.US,
+ "1 --- 5",
+ "5 --- 5",
+ "5 --- 5",
+ "0 --- 3",
+ "0 --- 0",
+ "3 --- 3,000",
+ "3,000 --- 5,000",
+ "4,999 --- 5,001",
+ "5,000 --- 5,000",
+ "5,000 --- 5,000,000");
+
+ assertFormatRange(
+ "Basic",
+ NumberRangeFormatter.with().numberFormatters(
+ NumberFormatter.with().grouping(GroupingStrategy.OFF),
+ null
+ ),
+ ULocale.US,
+ "1 --- 5",
+ "5 --- 5",
+ "5 --- 5",
+ "0 --- 3",
+ "0 --- 0",
+ "3 --- 3,000",
+ "3000 --- 5,000",
+ "4999 --- 5,001",
+ "5000 --- 5,000",
+ "5000 --- 5,000,000");
+
+ assertFormatRange(
+ "Basic",
+ NumberRangeFormatter.with().numberFormatters(
+ null,
+ NumberFormatter.with().grouping(GroupingStrategy.OFF)
+ ),
+ ULocale.US,
+ "1 --- 5",
+ "5 --- 5",
+ "5 --- 5",
+ "0 --- 3",
+ "0 --- 0",
+ "3 --- 3000",
+ "3,000 --- 5000",
+ "4,999 --- 5001",
+ "5,000 --- 5000",
+ "5,000 --- 5000000");
+ }
+
+ static void assertFormatRange(
+ String message,
+ UnlocalizedNumberRangeFormatter f,
+ ULocale locale,
+ String expected_10_50,
+ String expected_49_51,
+ String expected_50_50,
+ String expected_00_30,
+ String expected_00_00,
+ String expected_30_3K,
+ String expected_30K_50K,
+ String expected_49K_51K,
+ String expected_50K_50K,
+ String expected_50K_50M) {
+ LocalizedNumberRangeFormatter l = f.locale(locale);
+ assertFormattedRangeEquals(message, l, 1, 5, expected_10_50);
+ assertFormattedRangeEquals(message, l, 4.9999999, 5.0000001, expected_49_51);
+ assertFormattedRangeEquals(message, l, 5, 5, expected_50_50);
+ assertFormattedRangeEquals(message, l, 0, 3, expected_00_30);
+ assertFormattedRangeEquals(message, l, 0, 0, expected_00_00);
+ assertFormattedRangeEquals(message, l, 3, 3000, expected_30_3K);
+ assertFormattedRangeEquals(message, l, 3000, 5000, expected_30K_50K);
+ assertFormattedRangeEquals(message, l, 4999, 5001, expected_49K_51K);
+ assertFormattedRangeEquals(message, l, 5000, 5000, expected_50K_50K);
+ assertFormattedRangeEquals(message, l, 5e3, 5e6, expected_50K_50M);
+ }
+
+ private static void assertFormattedRangeEquals(String message, LocalizedNumberRangeFormatter l, Number first,
+ Number second, String expected) {
+ String actual1 = l.formatRange(first, second).toString();
+ assertEquals(message + ": " + first + ", " + second, expected, actual1);
+ }
+
+}