ICU-11276 Assorted Java NumberRangeFormatter API improvements.

This commit is contained in:
Shane Carr 2018-08-28 22:36:09 -07:00
parent 9924225ed6
commit cc842512fa
No known key found for this signature in database
GPG Key ID: FCED3B24AAB18B5C
5 changed files with 97 additions and 50 deletions

View File

@ -10,6 +10,7 @@ import java.util.Arrays;
import com.ibm.icu.impl.number.DecimalQuantity;
import com.ibm.icu.impl.number.NumberStringBuilder;
import com.ibm.icu.number.NumberRangeFormatter.RangeIdentityType;
import com.ibm.icu.util.ICUUncheckedIOException;
/**
@ -17,7 +18,7 @@ import com.ibm.icu.util.ICUUncheckedIOException;
* including a String, an AttributedCharacterIterator, and a BigDecimal.
*
* @author sffc
* @draft ICU 62
* @draft ICU 63
* @provisional This API might change or be removed in a future release.
* @see NumberRangeFormatter
*/
@ -27,10 +28,6 @@ public class FormattedNumberRange {
final DecimalQuantity second;
final RangeIdentityType identityType;
public static enum RangeIdentityType {
EQUAL_BEFORE_ROUNDING, EQUAL_AFTER_ROUNDING, NOT_EQUAL
}
FormattedNumberRange(NumberStringBuilder nsb, DecimalQuantity first, DecimalQuantity second,
RangeIdentityType identityType) {
this.nsb = nsb;
@ -89,8 +86,8 @@ public class FormattedNumberRange {
* multiple times, this method may be called repeatedly with the following pattern:
*
* <pre>
* FieldPosition fpos = new FieldPosition(NumberFormat.Field.GROUPING_SEPARATOR);
* while (formattedNumber.nextFieldPosition(fpos, status)) {
* FieldPosition fpos = new FieldPosition(NumberFormat.Field.INTEGER);
* while (formattedNumberRange.nextFieldPosition(fpos, status)) {
* // do something with fpos.
* }
* </pre>
@ -162,7 +159,7 @@ public class FormattedNumberRange {
* used. For example, if the first and second number were the same either before or after rounding occurred, an
* identity fallback was used.
*
* @return A IdentityType indicating the resulting identity situation in the formatted number range.
* @return A RangeIdentityType indicating the resulting identity situation in the formatted number range.
* @draft ICU 63
* @provisional This API might change or be removed in a future release.
* @see NumberRangeFormatter

View File

@ -6,7 +6,7 @@ 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.number.NumberRangeFormatter.RangeIdentityType;
/**
* A NumberRangeFormatter that has a locale associated with it; this means .formatRange() methods are available.
@ -30,7 +30,7 @@ public class LocalizedNumberRangeFormatter extends NumberRangeFormatterSettings<
* 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.
* @return A FormattedNumberRange object; call .toString() to get the string.
* @draft ICU 63
* @provisional This API might change or be removed in a future release.
* @see NumberRangeFormatter
@ -49,7 +49,7 @@ public class LocalizedNumberRangeFormatter extends NumberRangeFormatterSettings<
* 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.
* @return A FormattedNumberRange object; call .toString() to get the string.
* @draft ICU 63
* @provisional This API might change or be removed in a future release.
* @see NumberRangeFormatter
@ -70,7 +70,7 @@ public class LocalizedNumberRangeFormatter extends NumberRangeFormatterSettings<
* 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.
* @return A FormattedNumberRange object; call .toString() to get the string.
* @draft ICU 63
* @provisional This API might change or be removed in a future release.
* @see NumberRangeFormatter

View File

@ -8,6 +8,20 @@ import com.ibm.icu.util.ULocale;
/**
* The main entrypoint to the formatting of ranges of numbers, including currencies and other units of measurement.
* <p>
* Usage example:
* <p>
*
* <pre>
* NumberRangeFormatter.with().identityFallback(RangeIdentityFallback.APPROXIMATELY_OR_SINGLE_VALUE)
* .numberFormatterFirst(NumberFormatter.with().unit(MeasureUnit.METER))
* .numberFormatterSecond(NumberFormatter.with().unit(MeasureUnit.KILOMETER)).locale(ULocale.UK)
* .formatRange(750, 1.2).toString();
* // => "750 m - 1.2 km"
* </pre>
* <p>
* Like NumberFormatter, NumberRangeFormatter instances are immutable and thread-safe. This API is based on the
* <em>fluent</em> design pattern popularized by libraries such as Google's Guava.
*
* @author sffc
* @draft ICU 63
@ -72,7 +86,7 @@ public abstract class NumberRangeFormatter {
* @provisional This API might change or be removed in a future release.
* @see NumberRangeFormatter
*/
public enum IdentityFallback {
public static enum RangeIdentityFallback {
/**
* Show the number as a single value rather than a range. Example: "$5"
*
@ -114,41 +128,64 @@ public abstract class NumberRangeFormatter {
}
/**
* Defines the behavior when the two numbers in the range are identical after rounding. To programmatically detect
* when the identity fallback is used, compare the lower and upper BigDecimals via FormattedNumber.
* Used in the result class FormattedNumberRange to indicate to the user whether the numbers formatted in the range
* were equal or not, and whether or not the identity fallback was applied.
*
* @draft ICU 63
* @provisional This API might change or be removed in a future release.
* @see NumberRangeFormatter
*/
public static enum RangeIdentityFallback {
public static enum RangeIdentityType {
/**
* Show the number as a single value rather than a range. Example: "$5"
* Used to indicate that the two numbers in the range were equal, even before any rounding rules were applied.
*
* @draft ICU 63
* @provisional This API might change or be removed in a future release.
* @see NumberRangeFormatter
*/
SINGLE_VALUE,
EQUAL_BEFORE_ROUNDING,
/**
* Show the number using a locale-sensitive approximation pattern. If the numbers were the same before rounding,
* show the single value. Example: "~$5" or "$5"
* Used to indicate that the two numbers in the range were equal, but only after rounding rules were applied.
*
* @draft ICU 63
* @provisional This API might change or be removed in a future release.
* @see NumberRangeFormatter
*/
APPROXIMATELY_OR_SINGLE_VALUE,
EQUAL_AFTER_ROUNDING,
/**
* Show the number using a locale-sensitive approximation pattern. Use the range pattern always, even if the
* inputs are the same. Example: "~$5"
* Used to indicate that the two numbers in the range were not equal, even after rounding rules were applied.
*
* @draft ICU 63
* @provisional This API might change or be removed in a future release.
* @see NumberRangeFormatter
*/
APPROXIMATELY,
/**
* Show the number as the range of two equal values. Use the range pattern always, even if the inputs are the
* same. Example (with RangeCollapse.NONE): "$5 $5"
*/
RANGE
NOT_EQUAL
}
private static final UnlocalizedNumberRangeFormatter BASE = new UnlocalizedNumberRangeFormatter();
/**
* Call this method at the beginning of a NumberRangeFormatter fluent chain in which the locale is not currently
* known at the call site.
*
* @return An {@link UnlocalizedNumberRangeFormatter}, to be used for chaining.
* @draft ICU 63
*/
public static UnlocalizedNumberRangeFormatter with() {
return BASE;
}
/**
* Call this method at the beginning of a NumberRangeFormatter fluent chain in which the locale is known at the call
* site.
*
* @param locale
* The locale from which to load formats and symbols for number range formatting.
* @return A {@link LocalizedNumberRangeFormatter}, to be used for chaining.
* @draft ICU 63
*/
public static LocalizedNumberRangeFormatter withLocale(Locale locale) {
return BASE.locale(locale);
}

View File

@ -53,19 +53,35 @@ public abstract class NumberRangeFormatterSettings<T extends NumberRangeFormatte
* @see NumberFormatter
* @see NumberRangeFormatter
*/
public T numberFormatter(UnlocalizedNumberFormatter formatter) {
return numberFormatters(formatter, formatter);
public T numberFormatterBoth(UnlocalizedNumberFormatter formatter) {
return (T) numberFormatterFirst(formatter).numberFormatterSecond(formatter);
}
/**
* Sets the NumberFormatter instance to use for the first number in the range.
* <p>
* The NumberFormatter instance must not have a locale applied yet; the locale specified on the
* NumberRangeFormatter will be used.
*
* @param formatterFirst
* The formatter to use for the first number in the range.
* @return The fluent chain.
* @draft ICU 63
* @provisional This API might change or be removed in a future release.
* @see NumberFormatter
* @see NumberRangeFormatter
*/
public T numberFormatterFirst(UnlocalizedNumberFormatter formatterFirst) {
return create(KEY_FORMATTER_1, formatterFirst);
}
/**
* Sets the NumberFormatter instances to use for the numbers in the range. This method allows you to set a different
* formatter for the first and second numbers.
* <p>
* The NumberFormatter instances must not have a locale applied yet; the locale specified on the
* The NumberFormatter instance must not have a locale applied yet; the locale specified on the
* NumberRangeFormatter will be used.
*
* @param formatterFirst
* The formatter to use for the first number in the range.
* @param formatterSecond
* The formatter to use for the second number in the range.
* @return The fluent chain.
@ -74,9 +90,8 @@ public abstract class NumberRangeFormatterSettings<T extends NumberRangeFormatte
* @see NumberFormatter
* @see NumberRangeFormatter
*/
public T numberFormatters(UnlocalizedNumberFormatter formatterFirst, UnlocalizedNumberFormatter formatterSecond) {
T intermediate = create(KEY_FORMATTER_1, formatterFirst);
return (T) intermediate.create(KEY_FORMATTER_2, formatterSecond);
public T numberFormatterSecond(UnlocalizedNumberFormatter formatterSecond) {
return create(KEY_FORMATTER_2, formatterSecond);
}
/**
@ -113,7 +128,7 @@ public abstract class NumberRangeFormatterSettings<T extends NumberRangeFormatte
* <li>APPROXIMATELY: "~5 miles"</li>
* <li>RANGE: "5-5 miles" (with collapse=UNIT)</li>
* <p>
* The default value is AUTO.
* The default value is APPROXIMATELY.
*
* @param identityFallback
* The strategy to use when formatting two numbers that end up being the same.

View File

@ -61,7 +61,7 @@ public class NumberRangeFormatterTest {
public void testNullBehavior() {
assertFormatRange(
"Basic",
NumberRangeFormatter.with().numberFormatter(null),
NumberRangeFormatter.with().numberFormatterBoth(null),
ULocale.US,
"1 --- 5",
"5 --- 5",
@ -76,7 +76,7 @@ public class NumberRangeFormatterTest {
assertFormatRange(
"Basic",
NumberRangeFormatter.with().numberFormatters(null, null),
NumberRangeFormatter.with().numberFormatterFirst(null),
ULocale.US,
"1 --- 5",
"5 --- 5",
@ -91,10 +91,9 @@ public class NumberRangeFormatterTest {
assertFormatRange(
"Basic",
NumberRangeFormatter.with().numberFormatters(
NumberFormatter.with().grouping(GroupingStrategy.OFF),
null
),
NumberRangeFormatter.with()
.numberFormatterFirst(NumberFormatter.with().grouping(GroupingStrategy.OFF))
.numberFormatterSecond(null),
ULocale.US,
"1 --- 5",
"5 --- 5",
@ -109,10 +108,9 @@ public class NumberRangeFormatterTest {
assertFormatRange(
"Basic",
NumberRangeFormatter.with().numberFormatters(
null,
NumberFormatter.with().grouping(GroupingStrategy.OFF)
),
NumberRangeFormatter.with()
.numberFormatterFirst(null)
.numberFormatterSecond(NumberFormatter.with().grouping(GroupingStrategy.OFF)),
ULocale.US,
"1 --- 5",
"5 --- 5",