com.ibm.icu.text.ConstrainedFieldPosition Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of icu4j Show documentation
Show all versions of icu4j Show documentation
International Component for Unicode for Java (ICU4J) is a mature, widely used Java library
providing Unicode and Globalization support
// © 2018 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html#License
package com.ibm.icu.text;
import java.text.Format.Field;
import java.util.Objects;
/**
* Represents a span of a string containing a given field.
*
* This class differs from FieldPosition in the following ways:
*
* 1. It has information on the field category.
* 2. It allows you to set constraints to use when iterating over field positions.
* 3. It is used for the newer FormattedValue APIs.
*
* @author sffc
* @draft ICU 64
* @provisional This API might change or be removed in a future release.
*/
public class ConstrainedFieldPosition {
/**
* Represents the type of constraint for ConstrainedFieldPosition.
*
* Constraints are used to control the behavior of iteration in FormattedValue.
*/
private enum ConstraintType {
/**
* Represents the lack of a constraint.
*
* This is the value of fConstraint
* if no "constrain" methods were called.
*/
NONE,
/**
* Represents that the field class is constrained.
*
* This is the value of fConstraint
* after {@link #constrainClass} is called.
*
* FormattedValue implementations should not change the field class when this constraint is active.
*/
CLASS,
/**
* Represents that the field is constrained.
*
* This is the value of fConstraint
* after {@link #constrainField} is called.
*
* FormattedValue implementations should not change the field when this constraint is active.
*/
FIELD,
/**
* Represents that the field value is constrained.
*
* This is the value of fConstraint
* after {@link #constrainField} is called.
*
* FormattedValue implementations should not change the field or value with this constraint.
*/
VALUE
};
private ConstraintType fConstraint;
private Class> fClassConstraint;
private Field fField;
private Object fValue;
private int fStart;
private int fLimit;
private long fContext;
/**
* Initializes a CategoryFieldPosition.
*
* By default, the CategoryFieldPosition has no iteration constraints.
*
* @draft ICU 64
* @provisional This API might change or be removed in a future release.
*/
public ConstrainedFieldPosition() {
reset();
}
/**
* Resets this ConstrainedFieldPosition to its initial state, as if it were newly created:
*
* - Removes any constraints that may have been set on the instance.
* - Resets the iteration position.
*
* @draft ICU 64
* @provisional This API might change or be removed in a future release.
*/
public void reset() {
fConstraint = ConstraintType.NONE;
fClassConstraint = Object.class;
fField = null;
fValue = null;
fStart = 0;
fLimit = 0;
fContext = 0;
}
/**
* Sets a constraint on the field.
*
* When this instance of ConstrainedFieldPosition is passed to {@link FormattedValue#nextPosition}, positions are
* skipped unless they have the given field.
*
* Any previously set constraints are cleared.
*
* For example, to loop over all grouping separators:
*
*
* ConstrainedFieldPosition cfpos;
* cfpos.constrainField(NumberFormat.Field.GROUPING_SEPARATOR);
* while (fmtval.nextPosition(cfpos)) {
* // handle the grouping separator position
* }
*
*
* Changing the constraint while in the middle of iterating over a FormattedValue
* does not generally have well-defined behavior.
*
* @param field
* The field to fix when iterating.
* @draft ICU 64
* @provisional This API might change or be removed in a future release.
*/
public void constrainField(Field field) {
if (field == null) {
throw new IllegalArgumentException("Cannot constrain on null field");
}
fConstraint = ConstraintType.FIELD;
fClassConstraint = Object.class;
fField = field;
fValue = null;
}
/**
* Sets a constraint on the field class.
*
* When this instance of ConstrainedFieldPosition is passed to {@link FormattedValue#nextPosition}, positions are
* skipped unless the field is an instance of the class constraint, including subclasses.
*
* Any previously set constraints are cleared.
*
* For example, to loop over only the number-related fields:
*
*
* ConstrainedFieldPosition cfpos;
* cfpos.constrainClass(NumberFormat.Field.class);
* while (fmtval.nextPosition(cfpos)) {
* // handle the number-related field position
* }
*
*
* @param classConstraint
* The field class to fix when iterating.
* @draft ICU 64
* @provisional This API might change or be removed in a future release.
*/
public void constrainClass(Class> classConstraint) {
if (classConstraint == null) {
throw new IllegalArgumentException("Cannot constrain on null field class");
}
fConstraint = ConstraintType.CLASS;
fClassConstraint = classConstraint;
fField = null;
fValue = null;
}
/**
* Sets a constraint on field and field value.
*
* When this instance of ConstrainedFieldPosition is passed to {@link FormattedValue#nextPosition}, positions are
* skipped unless both the field and the field value are equal.
*
* Any previously set constraints are cleared.
*
* For example, to find the span a date interval corresponding to the first date:
*
*
* ConstrainedFieldPosition cfpos;
* cfpos.constrainFieldAndValue(DateIntervalFormat.SpanField.DATE_INTERVAL_SPAN, 0);
* while (fmtval.nextPosition(cfpos)) {
* // handle the span of the first date in the date interval
* }
*
*
* @param field The field to fix when iterating.
* @param fieldValue The field value to fix when iterating.
* @internal ICU 64 technology preview
* @deprecated This API is for technology preview and might be changed or removed in a future release.
*/
@Deprecated
public void constrainFieldAndValue(Field field, Object fieldValue) {
fConstraint = ConstraintType.VALUE;
fClassConstraint = Object.class;
fField = field;
fValue = fieldValue;
}
/**
* Gets the field for the current position.
*
* The return value is well-defined and non-null only after
* FormattedValue#nextPosition returns TRUE.
*
* @return The field saved in the instance. See above for null conditions.
* @draft ICU 64
* @provisional This API might change or be removed in a future release.
*/
public Field getField() {
return fField;
}
/**
* Gets the INCLUSIVE start index for the current position.
*
* The return value is well-defined only after FormattedValue#nextPosition returns TRUE.
*
* @return The start index saved in the instance.
* @draft ICU 64
* @provisional This API might change or be removed in a future release.
*/
public int getStart() {
return fStart;
}
/**
* Gets the EXCLUSIVE end index stored for the current position.
*
* The return value is well-defined only after FormattedValue#nextPosition returns TRUE.
*
* @return The end index saved in the instance.
* @draft ICU 64
* @provisional This API might change or be removed in a future release.
*/
public int getLimit() {
return fLimit;
}
/**
* Gets the value associated with the current field position. The field value is often not set.
*
* The return value is well-defined only after FormattedValue#nextPosition returns TRUE.
*
* @return The value for the current position. Might be null.
* @draft ICU 64
* @provisional This API might change or be removed in a future release.
*/
public Object getFieldValue() {
return fValue;
}
/**
* Gets an int64 that FormattedValue implementations may use for storage.
*
* The initial value is zero.
*
* Users of FormattedValue should not need to call this method.
*
* @return The current iteration context from {@link #setInt64IterationContext}.
* @draft ICU 64
* @provisional This API might change or be removed in a future release.
*/
public long getInt64IterationContext() {
return fContext;
}
/**
* Sets an int64 that FormattedValue implementations may use for storage.
*
* Intended to be used by FormattedValue implementations.
*
* @param context
* The new iteration context.
* @draft ICU 64
* @provisional This API might change or be removed in a future release.
*/
public void setInt64IterationContext(long context) {
fContext = context;
}
/**
* Sets new values for the primary public getters.
*
* Intended to be used by FormattedValue implementations.
*
* It is up to the implementation to ensure that the user-requested
* constraints are satisfied. This method does not check!
*
* @param field
* The new field.
* @param value
* The new field value. Should be null if there is no value.
* @param start
* The new inclusive start index.
* @param limit
* The new exclusive end index.
* @draft ICU 64
* @provisional This API might change or be removed in a future release.
*/
public void setState(Field field, Object value, int start, int limit) {
// Check matchesField only as an assertion (debug build)
assert matchesField(field, value);
fField = field;
fValue = value;
fStart = start;
fLimit = limit;
}
/**
* Determines whether a given field and value should be included given the
* constraints.
*
* Intended to be used by FormattedValue implementations.
*
* @param field The field to test.
* @param fieldValue The field value to test. Should be null if there is no value.
* @return Whether the field should be included given the constraints.
* @draft ICU 64
* @provisional This API might change or be removed in a future release.
*/
public boolean matchesField(Field field, Object fieldValue) {
if (field == null) {
throw new IllegalArgumentException("field must not be null");
}
switch (fConstraint) {
case NONE:
return true;
case CLASS:
return fClassConstraint.isAssignableFrom(field.getClass());
case FIELD:
return fField == field;
case VALUE:
// Note: Objects.equals is Android API level 19 and Java 1.7
return fField == field && Objects.equals(fValue, fieldValue);
default:
throw new AssertionError();
}
}
/**
* {@inheritDoc}
* @draft ICU 64
* @provisional This API might change or be removed in a future release.
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("CFPos[");
sb.append(fStart);
sb.append('-');
sb.append(fLimit);
sb.append(' ');
sb.append(fField);
sb.append(']');
return sb.toString();
}
}