diff --git a/src/java.base/share/classes/java/text/ListFormat.java b/src/java.base/share/classes/java/text/ListFormat.java index 3f320bbcc9b..29e58ea717c 100644 --- a/src/java.base/share/classes/java/text/ListFormat.java +++ b/src/java.base/share/classes/java/text/ListFormat.java @@ -84,9 +84,9 @@ import sun.util.locale.provider.LocaleProviderAdapter; * Note: these examples are from CLDR, there could be different results from other locale providers. *
* Alternatively, Locale, Type, and/or Style independent instances - * can be created with {@link #getInstance(String[])}. The String array to the - * method specifies the delimiting patterns for the start/middle/end portion of - * the formatted string, as well as optional specialized patterns for two or three + * can be created with {@link #getInstance(String[])}. The String array passed to the + * method specifies the delimiting patterns for the {@code start}/{@code middle}/{@code end} + * portion of the formatted string, as well as optional specialized patterns for two or three * elements. Refer to the method description for more detail. *
* On parsing, if some ambiguity is found in the input string, such as delimiting @@ -121,7 +121,8 @@ public final class ListFormat extends Format { /** * The array of five pattern Strings. Each element corresponds to the Unicode LDML's - * `listPatternsPart` type, i.e, start/middle/end/two/three. + * {@code listPatternPart} type, i.e, + * {@code start}/{@code middle}/{@code end}/{@code two}/{@code three}. * @serial */ private final String[] patterns; @@ -153,6 +154,7 @@ public final class ListFormat extends Format { var pattern = patterns[START]; var placeholderPositions = findPlaceholders(pattern); if (placeholderPositions != null && + placeholderPositions[2] == -1 && placeholderPositions[1] + PLACEHOLDER_LENGTH == pattern.length()) { startBefore = pattern.substring(0, placeholderPositions[0]); startBetween = pattern.substring(placeholderPositions[0] + PLACEHOLDER_LENGTH, @@ -164,6 +166,7 @@ public final class ListFormat extends Format { pattern = patterns[MIDDLE]; placeholderPositions = findPlaceholders(pattern); if (placeholderPositions != null && + placeholderPositions[2] == -1 && placeholderPositions[0] == 0 && placeholderPositions[1] + PLACEHOLDER_LENGTH == pattern.length()) { middleBetween = pattern.substring(placeholderPositions[0] + PLACEHOLDER_LENGTH, @@ -174,7 +177,9 @@ public final class ListFormat extends Format { pattern = patterns[END]; placeholderPositions = findPlaceholders(pattern); - if (placeholderPositions != null && placeholderPositions[0] == 0) { + if (placeholderPositions != null && + placeholderPositions[2] == -1 && + placeholderPositions[0] == 0) { endBetween = pattern.substring(placeholderPositions[0] + PLACEHOLDER_LENGTH, placeholderPositions[1]); endAfter = pattern.substring(placeholderPositions[1] + PLACEHOLDER_LENGTH); @@ -185,7 +190,8 @@ public final class ListFormat extends Format { // Validate two/three patterns, if given. Otherwise, generate them pattern = patterns[TWO]; if (!pattern.isEmpty()) { - if (findPlaceholders(pattern) == null) { + placeholderPositions = findPlaceholders(pattern); + if (placeholderPositions == null || placeholderPositions[2] >= 0) { throw new IllegalArgumentException("pattern for two is incorrect: " + pattern); } } else { @@ -245,36 +251,43 @@ public final class ListFormat extends Format { * instead of letting the runtime provide appropriate patterns for the {@code Locale}, * {@code Type}, or {@code Style}. *
- * The patterns array should contain five String patterns, each corresponding to the Unicode LDML's - * {@code listPatternPart}, i.e., "start", "middle", "end", two element, and three element patterns - * in this order. Each pattern contains "{0}" and "{1}" (and "{2}" for the three element pattern) - * placeholders that are substituted with the passed input strings on formatting. - * If the length of the patterns array is not 5, an {@code IllegalArgumentException} - * is thrown. + * The patterns array should contain five String patterns, each corresponding + * to the Unicode LDML's {@code listPatternPart}, i.e., {@code start}, + * {@code middle}, {@code end}, {@code two} element, and {@code three} + * element patterns in this order. Each pattern contains "{0}" and "{1}" + * (and "{2}" for the {@code three} element pattern) placeholders that are + * substituted with the passed input strings on formatting. If the length of + * the patterns array is not 5, an {@code IllegalArgumentException} is thrown. *
* Each pattern string is first parsed as follows. Literals in parentheses, such as * "start_before", are optional: - *
+ * {@snippet :
* start := (start_before){0}start_between{1}
* middle := {0}middle_between{1}
* end := {0}end_between{1}(end_after)
* two := (two_before){0}two_between{1}(two_after)
* three := (three_before){0}three_between1{1}three_between2{2}(three_after)
- *
- * If two or three pattern string is empty, it falls back to
- * {@code "(start_before){0}end_between{1}(end_after)"},
- * {@code "(start_before){0}start_between{1}end_between{2}(end_after)"} respectively.
- * If parsing of any pattern string for start, middle, end, two, or three fails,
+ * }
+ * If the {@code two} or {@code three} pattern string is empty, it falls back to
+ * {@snippet :
+ * (start_before){0}end_between{1}(end_after)
+ * (start_before){0}start_between{1}end_between{2}(end_after)
+ * }
+ * respectively.
+ * If parsing of any pattern string for {@code start}, {@code middle},
+ * {@code end}, {@code two}, or {@code three} fails, including duplicate
+ * placeholders, "{2}" in patterns other than the {@code three} element
+ * pattern, or any use of "{" or "}" other than "{0}", "{1}", or "{2}",
* it throws an {@code IllegalArgumentException}.
* * On formatting, the input string list with {@code n} elements substitutes above * placeholders based on the number of elements: - *
+ * {@snippet :
* n = 1: {0}
* n = 2: parsed pattern for "two"
* n = 3: parsed pattern for "three"
* n > 3: (start_before){0}start_between{1}middle_between{2} ... middle_between{m}end_between{n}(end_after)
- *
+ * }
* As an example, the following table shows a pattern array which is equivalent to
* {@code STANDARD} type, {@code FULL} style in US English:
*