/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package java.text; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Locale; import libcore.util.EmptyArray; /** * Returns a fixed string based on a numeric value. The class can be used in * conjunction with the {@link MessageFormat} class to handle plurals in * messages. {@code ChoiceFormat} enables users to attach a format to a range of * numbers. The choice is specified with an ascending list of doubles, where * each item specifies a half-open interval up to the next item as in the * following: X matches j if and only if {@code limit[j] <= X < limit[j+1]}. *
* If there is no match, then either the first or last index is used. The first * or last index is used depending on whether the number is too low or too high. * The length of the format array must be the same as the length of the limits * array. *
* *** double[] limits = {1, 2, 3, 4, 5, 6, 7}; * String[] fmts = {"Sun", "Mon", "Tue", "Wed", "Thur", "Fri", "Sat"}; * * double[] limits2 = {0, 1, ChoiceFormat.nextDouble(1)}; * String[] fmts2 = {"no files", "one file", "many files"}; **
* ChoiceFormat.nextDouble(double) allows to get the double following the one * passed to the method. This is used to create half open intervals. *
* {@code ChoiceFormat} objects also may be converted to and from patterns. * The conversion can be done programmatically, as in the example above, or * by using a pattern like the following: *
* *** "1#Sun|2#Mon|3#Tue|4#Wed|5#Thur|6#Fri|7#Sat" * "0#are no files|1#is one file|1<are many files" ** *
* where: *
* The length of the {@code limits} and {@code formats} arrays must be the
* same.
*
* @param limits
* an array of doubles in ascending order. The lowest and highest
* possible values are negative and positive infinity.
* @param formats
* the strings associated with the ranges defined through {@code
* limits}. The lower bound of the associated range is at the
* same index as the string.
*/
public ChoiceFormat(double[] limits, String[] formats) {
setChoices(limits, formats);
}
/**
* Constructs a new {@code ChoiceFormat} with the strings and limits parsed
* from the specified pattern.
*
* @param template
* the pattern of strings and ranges.
* @throws IllegalArgumentException
* if an error occurs while parsing the pattern.
*/
public ChoiceFormat(String template) {
applyPattern(template);
}
/**
* Parses the pattern to determine new strings and ranges for this
* {@code ChoiceFormat}.
*
* @param template
* the pattern of strings and ranges.
* @throws IllegalArgumentException
* if an error occurs while parsing the pattern.
*/
public void applyPattern(String template) {
double[] limits = new double[5];
List
* If one of the format strings of this {@code ChoiceFormat} instance is
* found in {@code string} starting at {@code position.getIndex()} then
*
* If none of the format strings is found in {@code string} then
*
* The length of the {@code limits} and {@code formats} arrays must be the
* same.
*
* @param limits
* an array of doubles in ascending order. The lowest and highest
* possible values are negative and positive infinity.
* @param formats
* the strings associated with the ranges defined through {@code
* limits}. The lower bound of the associated range is at the
* same index as the string.
*/
public void setChoices(double[] limits, String[] formats) {
if (limits.length != formats.length) {
throw new IllegalArgumentException("limits.length != formats.length: " +
limits.length + " != " + formats.length);
}
choiceLimits = limits;
choiceFormats = formats;
}
private int skipWhitespace(String string, int index) {
int length = string.length();
while (index < length && Character.isWhitespace(string.charAt(index))) {
index++;
}
return index;
}
/**
* Returns the pattern of this {@code ChoiceFormat} which specifies the
* ranges and their associated strings.
*
* @return the pattern.
*/
public String toPattern() {
StringBuilder buffer = new StringBuilder();
for (int i = 0; i < choiceLimits.length; i++) {
if (i != 0) {
buffer.append('|');
}
String previous = String.valueOf(previousDouble(choiceLimits[i]));
String limit = String.valueOf(choiceLimits[i]);
if (previous.length() < limit.length()) {
buffer.append(previous);
buffer.append('<');
} else {
buffer.append(limit);
buffer.append('#');
}
boolean quote = (choiceFormats[i].indexOf('|') != -1);
if (quote) {
buffer.append('\'');
}
buffer.append(choiceFormats[i]);
if (quote) {
buffer.append('\'');
}
}
return buffer.toString();
}
}
*
*
*
* @param string
* the source string to parse.
* @param position
* input/output parameter, specifies the start index in {@code
* string} from where to start parsing. See the Returns
* section for a description of the output values.
* @return a Double resulting from the parse, or Double.NaN if there is an
* error
*/
@Override
public Number parse(String string, ParsePosition position) {
int offset = position.getIndex();
for (int i = 0; i < choiceFormats.length; i++) {
if (string.startsWith(choiceFormats[i], offset)) {
position.setIndex(offset + choiceFormats[i].length());
return new Double(choiceLimits[i]);
}
}
position.setErrorIndex(offset);
return new Double(Double.NaN);
}
/**
* Returns the double value which is closest to the specified double but
* smaller.
*
* @param value
* a double value.
* @return the next smaller double value.
*/
public static final double previousDouble(double value) {
if (value == Double.NEGATIVE_INFINITY) {
return value;
}
long bits;
// Handle 0.0
if (value == 0) {
bits = 0x8000000000000000L;
} else {
bits = Double.doubleToLongBits(value);
}
return Double.longBitsToDouble(value <= 0 ? bits + 1 : bits - 1);
}
/**
* Sets the double values and associated strings of this ChoiceFormat. When
* calling {@link #format(double, StringBuffer, FieldPosition) format} with
* a double value {@code d}, then the element {@code i} in {@code formats}
* is selected where {@code i} fulfills
* {@code limits[i] <= d < limits[i+1]}.
*