blob: 09da4247e37f2409c7a174ab9b2003d76fe8a674 [file] [log] [blame]
// © 2017 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html#License
package com.ibm.icu.number;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.AttributedCharacterIterator;
import java.text.FieldPosition;
import java.util.Arrays;
import com.ibm.icu.impl.number.DecimalQuantity;
import com.ibm.icu.impl.number.NumberStringBuilder;
import com.ibm.icu.text.ConstrainedFieldPosition;
import com.ibm.icu.text.FormattedValue;
import com.ibm.icu.text.PluralRules.IFixedDecimal;
import com.ibm.icu.util.ICUUncheckedIOException;
/**
* The result of a number formatting operation. This class allows the result to be exported in several
* data types, including a String, an AttributedCharacterIterator, and a BigDecimal.
*
* @draft ICU 60
* @provisional This API might change or be removed in a future release.
* @see NumberFormatter
*/
public class FormattedNumber implements FormattedValue {
final NumberStringBuilder nsb;
final DecimalQuantity fq;
FormattedNumber(NumberStringBuilder nsb, DecimalQuantity fq) {
this.nsb = nsb;
this.fq = fq;
}
/**
* {@inheritDoc}
*
* @draft ICU 60
* @provisional This API might change or be removed in a future release.
*/
@Override
public String toString() {
return nsb.toString();
}
/**
* {@inheritDoc}
*
* @return The same Appendable, for chaining.
* @draft ICU 60
*/
@Override
public <A extends Appendable> A appendTo(A appendable) {
try {
appendable.append(nsb);
} catch (IOException e) {
// Throw as an unchecked exception to avoid users needing try/catch
throw new ICUUncheckedIOException(e);
}
return appendable;
}
/**
* {@inheritDoc}
*
* @draft ICU 64
* @provisional This API might change or be removed in a future release.
*/
@Override
public char charAt(int index) {
return nsb.charAt(index);
}
/**
* {@inheritDoc}
*
* @draft ICU 64
* @provisional This API might change or be removed in a future release.
*/
@Override
public int length() {
return nsb.length();
}
/**
* {@inheritDoc}
*
* @draft ICU 64
* @provisional This API might change or be removed in a future release.
*/
@Override
public CharSequence subSequence(int start, int end) {
return nsb.subString(start, end);
}
/**
* {@inheritDoc}
*
* @draft ICU 64
* @provisional This API might change or be removed in a future release.
*/
@Override
public boolean nextPosition(ConstrainedFieldPosition cfpos) {
return nsb.nextPosition(cfpos, null);
}
/**
* Determines the start (inclusive) and end (exclusive) indices of the next occurrence of the
* given <em>field</em> in the output string. This allows you to determine the locations of,
* for example, the integer part, fraction part, or symbols.
* <p>
* This is a simpler but less powerful alternative to {@link #nextPosition}.
* <p>
* If a field occurs just once, calling this method will find that occurrence and return it. If a
* field occurs 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)) {
* // do something with fpos.
* }
* </pre>
* <p>
* This method is useful if you know which field to query. If you want all available field position
* information, use {@link #nextPosition} or {@link #toCharacterIterator()}.
*
* @param fieldPosition
* Input+output variable. On input, the "field" property determines which field to look
* up, and the "beginIndex" and "endIndex" properties determine where to begin the search.
* On output, the "beginIndex" is set to the beginning of the first occurrence of the
* field with either begin or end indices after the input indices, "endIndex" is set to
* the end of that occurrence of the field (exclusive index). If a field position is not
* found, the method returns FALSE and the FieldPosition may or may not be changed.
* @return true if a new occurrence of the field was found; false otherwise.
* @draft ICU 62
* @provisional This API might change or be removed in a future release.
* @see com.ibm.icu.text.NumberFormat.Field
* @see NumberFormatter
*/
public boolean nextFieldPosition(FieldPosition fieldPosition) {
fq.populateUFieldPosition(fieldPosition);
return nsb.nextFieldPosition(fieldPosition);
}
/**
* {@inheritDoc}
*
* @draft ICU 62
* @provisional This API might change or be removed in a future release.
*/
@Override
public AttributedCharacterIterator toCharacterIterator() {
return nsb.toCharacterIterator(null);
}
/**
* Export the formatted number as a BigDecimal. This endpoint is useful for obtaining the exact
* number being printed after scaling and rounding have been applied by the number formatting
* pipeline.
*
* @return A BigDecimal representation of the formatted number.
* @draft ICU 60
* @provisional This API might change or be removed in a future release.
* @see NumberFormatter
*/
public BigDecimal toBigDecimal() {
return fq.toBigDecimal();
}
/**
* @internal
* @deprecated This API is ICU internal only.
*/
@Deprecated
public IFixedDecimal getFixedDecimal() {
return fq;
}
/**
* {@inheritDoc}
*
* @draft ICU 60
* @provisional This API might change or be removed in a future release.
*/
@Override
public int hashCode() {
// NumberStringBuilder and BigDecimal are mutable, so we can't call
// #equals() or #hashCode() on them directly.
return Arrays.hashCode(nsb.toCharArray())
^ Arrays.hashCode(nsb.toFieldArray())
^ fq.toBigDecimal().hashCode();
}
/**
* {@inheritDoc}
*
* @draft ICU 60
* @provisional This API might change or be removed in a future release.
*/
@Override
public boolean equals(Object other) {
if (this == other)
return true;
if (other == null)
return false;
if (!(other instanceof FormattedNumber))
return false;
// NumberStringBuilder and BigDecimal are mutable, so we can't call
// #equals() or #hashCode() on them directly.
FormattedNumber _other = (FormattedNumber) other;
return Arrays.equals(nsb.toCharArray(), _other.nsb.toCharArray())
&& Arrays.equals(nsb.toFieldArray(), _other.nsb.toFieldArray())
&& fq.toBigDecimal().equals(_other.fq.toBigDecimal());
}
}