mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 06:45:07 +02:00
6285888: ChoiceFormat can support unescaped relational symbols in the Format segment
Reviewed-by: naoto
This commit is contained in:
parent
144a08ee50
commit
d3c3194ac3
3 changed files with 153 additions and 65 deletions
|
@ -68,71 +68,18 @@ import java.util.Arrays;
|
|||
* doesn't require any complex setup for a given locale. In fact,
|
||||
* {@code ChoiceFormat} doesn't implement any locale specific behavior.
|
||||
*
|
||||
* <p>
|
||||
* A {@code ChoiceFormat} can be constructed using either an array of formats
|
||||
* and an array of limits or a string pattern. When constructing with
|
||||
* format and limit arrays, the length of these arrays must be the same.
|
||||
*
|
||||
* For example,
|
||||
* <ul>
|
||||
* <li>
|
||||
* <em>limits</em> = {1,2,3,4,5,6,7}<br>
|
||||
* <em>formats</em> = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"}
|
||||
* <li>
|
||||
* <em>limits</em> = {0, 1, ChoiceFormat.nextDouble(1)}<br>
|
||||
* <em>formats</em> = {"no files", "one file", "many files"}<br>
|
||||
* ({@code nextDouble} can be used to get the next higher double, to
|
||||
* make the half-open interval.)
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* Below is an example of constructing a ChoiceFormat with arrays to format
|
||||
* and parse values:
|
||||
* {@snippet lang=java :
|
||||
* double[] limits = {1,2,3,4,5,6,7};
|
||||
* String[] dayOfWeekNames = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"};
|
||||
* ChoiceFormat form = new ChoiceFormat(limits, dayOfWeekNames);
|
||||
* ParsePosition status = new ParsePosition(0);
|
||||
* for (double i = 0.0; i <= 8.0; ++i) {
|
||||
* status.setIndex(0);
|
||||
* System.out.println(i + " -> " + form.format(i) + " -> "
|
||||
* + form.parse(form.format(i),status));
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* <p>
|
||||
* For more sophisticated patterns, {@code ChoiceFormat} can be used with
|
||||
* {@link MessageFormat} to produce accurate forms for singular and plural:
|
||||
* {@snippet lang=java :
|
||||
* MessageFormat msgFmt = new MessageFormat("The disk \"{0}\" contains {1}.");
|
||||
* double[] fileLimits = {0,1,2};
|
||||
* String[] filePart = {"no files","one file","{1,number} files"};
|
||||
* ChoiceFormat fileChoices = new ChoiceFormat(fileLimits, filePart);
|
||||
* msgFmt.setFormatByArgumentIndex(1, fileChoices);
|
||||
* Object[] args = {"MyDisk", 1273};
|
||||
* System.out.println(msgFmt.format(args));
|
||||
* }
|
||||
* The output with different values for {@code fileCount}:
|
||||
* <blockquote><pre>
|
||||
* The disk "MyDisk" contains no files.
|
||||
* The disk "MyDisk" contains one file.
|
||||
* The disk "MyDisk" contains 1,273 files.
|
||||
* </pre></blockquote>
|
||||
* See {@link MessageFormat##pattern_caveats MessageFormat} for caveats regarding
|
||||
* {@code MessageFormat} patterns within a {@code ChoiceFormat} pattern.
|
||||
*
|
||||
* <h2><a id="patterns">Patterns</a></h2>
|
||||
* A {@code ChoiceFormat} pattern has the following syntax:
|
||||
* <blockquote>
|
||||
* <dl>
|
||||
* <dt><i>Pattern:</i>
|
||||
* <dd>SubPattern *("|" SubPattern)
|
||||
* <dd><i>Note: Each additional SubPattern must have a Limit greater than the previous SubPattern's Limit</i>
|
||||
* </dl>
|
||||
*
|
||||
* <dl>
|
||||
* <dt><i>SubPattern:</i>
|
||||
* <dd>Limit Relation Format
|
||||
* <dd><sub>Note: Each additional SubPattern must have an ascending Limit-Relation interval</sub></dd>
|
||||
* </dl>
|
||||
*
|
||||
* <dl>
|
||||
|
@ -172,20 +119,54 @@ import java.util.Arrays;
|
|||
*
|
||||
* <dl>
|
||||
* <dt><i>Format:</i>
|
||||
* <dd>Any characters except the <i>Relation</i> symbols
|
||||
* <dd>Any characters except the special pattern character '|'
|
||||
* </dl>
|
||||
*
|
||||
* </blockquote>
|
||||
*
|
||||
* <i>Note:The relation ≤ is not equivalent to <=</i>
|
||||
*
|
||||
* <p>If a <i>Relation</i> symbol is to be used within a <i>Format</i> pattern,
|
||||
* it must be single quoted. For example,
|
||||
* {@code new ChoiceFormat("1# '#'1 ").format(1)} returns {@code " #1 "}.
|
||||
* <p> To use a reserved special pattern character within a <i>Format</i> pattern,
|
||||
* it must be single quoted. For example, {@code new ChoiceFormat("1#'|'foo'|'").format(1)}
|
||||
* returns {@code "|foo|"}.
|
||||
* Use two single quotes in a row to produce a literal single quote. For example,
|
||||
* {@code new ChoiceFormat("1# ''one'' ").format(1)} returns {@code " 'one' "}.
|
||||
*
|
||||
* <p>Below is an example of constructing a ChoiceFormat with a pattern:
|
||||
* <h2>Usage Information</h2>
|
||||
*
|
||||
* <p>
|
||||
* A {@code ChoiceFormat} can be constructed using either an array of formats
|
||||
* and an array of limits or a string pattern. When constructing with
|
||||
* format and limit arrays, the length of these arrays must be the same.
|
||||
*
|
||||
* For example,
|
||||
* <ul>
|
||||
* <li>
|
||||
* <em>limits</em> = {1,2,3,4,5,6,7}<br>
|
||||
* <em>formats</em> = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"}
|
||||
* <li>
|
||||
* <em>limits</em> = {0, 1, ChoiceFormat.nextDouble(1)}<br>
|
||||
* <em>formats</em> = {"no files", "one file", "many files"}<br>
|
||||
* ({@code nextDouble} can be used to get the next higher double, to
|
||||
* make the half-open interval.)
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* Below is an example of constructing a ChoiceFormat with arrays to format
|
||||
* and parse values:
|
||||
* {@snippet lang=java :
|
||||
* double[] limits = {1,2,3,4,5,6,7};
|
||||
* String[] dayOfWeekNames = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"};
|
||||
* ChoiceFormat form = new ChoiceFormat(limits, dayOfWeekNames);
|
||||
* ParsePosition status = new ParsePosition(0);
|
||||
* for (double i = 0.0; i <= 8.0; ++i) {
|
||||
* status.setIndex(0);
|
||||
* System.out.println(i + " -> " + form.format(i) + " -> "
|
||||
* + form.parse(form.format(i),status));
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* <p>Below is an example of constructing a ChoiceFormat with a String pattern:
|
||||
* {@snippet lang=java :
|
||||
* ChoiceFormat fmt = new ChoiceFormat(
|
||||
* "-1#is negative| 0#is zero or fraction | 1#is one |1.0<is 1+ |2#is two |2<is more than 2.");
|
||||
|
@ -202,6 +183,27 @@ import java.util.Arrays;
|
|||
* System.out.println(fmt.format(Double.POSITIVE_INFINITY)); // outputs "is more than 2."
|
||||
* }
|
||||
*
|
||||
* <p>
|
||||
* For more sophisticated patterns, {@code ChoiceFormat} can be used with
|
||||
* {@link MessageFormat} to produce accurate forms for singular and plural:
|
||||
* {@snippet lang=java :
|
||||
* MessageFormat msgFmt = new MessageFormat("The disk \"{0}\" contains {1}.");
|
||||
* double[] fileLimits = {0,1,2};
|
||||
* String[] filePart = {"no files","one file","{1,number} files"};
|
||||
* ChoiceFormat fileChoices = new ChoiceFormat(fileLimits, filePart);
|
||||
* msgFmt.setFormatByArgumentIndex(1, fileChoices);
|
||||
* Object[] args = {"MyDisk", 1273};
|
||||
* System.out.println(msgFmt.format(args));
|
||||
* }
|
||||
* The output with different values for {@code fileCount}:
|
||||
* <blockquote><pre>
|
||||
* The disk "MyDisk" contains no files.
|
||||
* The disk "MyDisk" contains one file.
|
||||
* The disk "MyDisk" contains 1,273 files.
|
||||
* </pre></blockquote>
|
||||
* See {@link MessageFormat##pattern_caveats MessageFormat} for caveats regarding
|
||||
* {@code MessageFormat} patterns within a {@code ChoiceFormat} pattern.
|
||||
*
|
||||
* <h2><a id="synchronization">Synchronization</a></h2>
|
||||
*
|
||||
* <p>
|
||||
|
@ -254,7 +256,7 @@ public class ChoiceFormat extends NumberFormat {
|
|||
double[] newChoiceLimits = new double[30];
|
||||
String[] newChoiceFormats = new String[30];
|
||||
int count = 0;
|
||||
int part = 0;
|
||||
int part = 0; // 0 denotes limit, 1 denotes format
|
||||
double startValue = 0;
|
||||
double oldStartValue = Double.NaN;
|
||||
boolean inQuote = false;
|
||||
|
@ -270,7 +272,10 @@ public class ChoiceFormat extends NumberFormat {
|
|||
}
|
||||
} else if (inQuote) {
|
||||
segments[part].append(ch);
|
||||
} else if (ch == '<' || ch == '#' || ch == '\u2264') {
|
||||
} else if (part == 0 && (ch == '<' || ch == '#' || ch == '\u2264')) {
|
||||
// Only consider relational symbols if parsing the limit segment (part == 0).
|
||||
// Don't treat a relational symbol as syntactically significant
|
||||
// when parsing Format segment (part == 1)
|
||||
if (segments[0].length() == 0) {
|
||||
throw new IllegalArgumentException("Each interval must"
|
||||
+ " contain a number before a format");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue