MessagePattern

public final class MessagePattern extends Object
implements Cloneable Freezable<MessagePattern>

Parses and represents ICU MessageFormat patterns. Also handles patterns for ChoiceFormat, PluralFormat and SelectFormat. Used in the implementations of those classes as well as in tools for message validation, translation and format conversion.

The parser handles all syntax relevant for identifying message arguments. This includes "complex" arguments whose style strings contain nested MessageFormat pattern substrings. For "simple" arguments (with no nested MessageFormat pattern substrings), the argument style is not parsed any further.

The parser handles named and numbered message arguments and allows both in one message.

Once a pattern has been parsed successfully, iterate through the parsed data with countParts(), getPart() and related methods.

The data logically represents a parse tree, but is stored and accessed as a list of "parts" for fast and simple parsing and to minimize object allocations. Arguments and nested messages are best handled via recursion. For every _START "part", getLimitPartIndex(int) efficiently returns the index of the corresponding _LIMIT "part".

List of "parts":

 message = MSG_START (SKIP_SYNTAX | INSERT_CHAR | REPLACE_NUMBER | argument)* MSG_LIMIT
 argument = noneArg | simpleArg | complexArg
 complexArg = choiceArg | pluralArg | selectArg

 noneArg = ARG_START.NONE (ARG_NAME | ARG_NUMBER) ARG_LIMIT.NONE
 simpleArg = ARG_START.SIMPLE (ARG_NAME | ARG_NUMBER) ARG_TYPE [ARG_STYLE] ARG_LIMIT.SIMPLE
 choiceArg = ARG_START.CHOICE (ARG_NAME | ARG_NUMBER) choiceStyle ARG_LIMIT.CHOICE
 pluralArg = ARG_START.PLURAL (ARG_NAME | ARG_NUMBER) pluralStyle ARG_LIMIT.PLURAL
 selectArg = ARG_START.SELECT (ARG_NAME | ARG_NUMBER) selectStyle ARG_LIMIT.SELECT

 choiceStyle = ((ARG_INT | ARG_DOUBLE) ARG_SELECTOR message)+
 pluralStyle = [ARG_INT | ARG_DOUBLE] (ARG_SELECTOR [ARG_INT | ARG_DOUBLE] message)+
 selectStyle = (ARG_SELECTOR message)+
 
  • Literal output text is not represented directly by "parts" but accessed between parts of a message, from one part's getLimit() to the next part's getIndex().
  • ARG_START.CHOICE stands for an ARG_START Part with ArgType CHOICE.
  • In the choiceStyle, the ARG_SELECTOR has the '<', the '#' or the less-than-or-equal-to sign (U+2264).
  • In the pluralStyle, the first, optional numeric Part has the "offset:" value. The optional numeric Part between each (ARG_SELECTOR, message) pair is the value of an explicit-number selector like "=2", otherwise the selector is a non-numeric identifier.
  • The REPLACE_NUMBER Part can occur only in an immediate sub-message of the pluralStyle.

This class is not intended for public subclassing.

Nested Class Summary

enum MessagePattern.ApostropheMode Mode for when an apostrophe starts quoted literal text for MessageFormat output. 
enum MessagePattern.ArgType Argument type constants. 
class MessagePattern.Part A message pattern "part", representing a pattern parsing event. 

Constant Summary

int ARG_NAME_NOT_NUMBER Return value from validateArgumentName(String) for when the string is a valid "pattern identifier" but not a number.
int ARG_NAME_NOT_VALID Return value from validateArgumentName(String) for when the string is invalid.
double NO_NUMERIC_VALUE Special value that is returned by getNumericValue(Part) when no numeric value is defined for a part.

Public Constructor Summary

MessagePattern()
Constructs an empty MessagePattern with default ApostropheMode.
MessagePattern(MessagePattern.ApostropheMode mode)
Constructs an empty MessagePattern.
MessagePattern(String pattern)
Constructs a MessagePattern with default ApostropheMode and parses the MessageFormat pattern string.

Public Method Summary

String
autoQuoteApostropheDeep()
Returns a version of the parsed pattern string where each ASCII apostrophe is doubled (escaped) if it is not already, and if it is not interpreted as quoting syntax.
void
clear()
Clears this MessagePattern.
void
clearPatternAndSetApostropheMode(MessagePattern.ApostropheMode mode)
Clears this MessagePattern and sets the ApostropheMode.
Object
clone()
Creates and returns a copy of this object.
MessagePattern
cloneAsThawed()
Creates and returns an unfrozen copy of this object.
int
countParts()
Returns the number of "parts" created by parsing the pattern string.
boolean
equals(Object other)
Compares this instance with the specified object and indicates if they are equal.
MessagePattern
freeze()
Freezes this object, making it immutable and thread-safe.
MessagePattern.ApostropheMode
int
getLimitPartIndex(int start)
Returns the index of the ARG|MSG_LIMIT part corresponding to the ARG|MSG_START at start.
double
getNumericValue(MessagePattern.Part part)
Returns the numeric value associated with an ARG_INT or ARG_DOUBLE.
MessagePattern.Part
getPart(int i)
Gets the i-th pattern "part".
MessagePattern.Part.Type
getPartType(int i)
Returns the Part.Type of the i-th pattern "part".
int
getPatternIndex(int partIndex)
Returns the pattern index of the specified pattern "part".
String
double
getPluralOffset(int pluralStart)
Returns the "offset:" value of a PluralFormat argument, or 0 if none is specified.
String
getSubstring(MessagePattern.Part part)
Returns the substring of the pattern string indicated by the Part.
boolean
hasNamedArguments()
Does the parsed pattern have named arguments like {first_name}?
boolean
hasNumberedArguments()
Does the parsed pattern have numbered arguments like {2}?
int
hashCode()
Returns an integer hash code for this object.
boolean
isFrozen()
Determines whether this object is frozen (immutable) or not.
MessagePattern
parse(String pattern)
Parses a MessageFormat pattern string.
MessagePattern
parseChoiceStyle(String pattern)
Parses a ChoiceFormat pattern string.
MessagePattern
parsePluralStyle(String pattern)
Parses a PluralFormat pattern string.
MessagePattern
parseSelectStyle(String pattern)
Parses a SelectFormat pattern string.
boolean
partSubstringMatches(MessagePattern.Part part, String s)
Compares the part's substring with the input string s.
String
toString()
Returns a string containing a concise, human-readable description of this object.
static int
validateArgumentName(String name)
Validates and parses an argument name or argument number string.

Inherited Method Summary

Constants

public static final int ARG_NAME_NOT_NUMBER

Return value from validateArgumentName(String) for when the string is a valid "pattern identifier" but not a number.

Constant Value: -1

public static final int ARG_NAME_NOT_VALID

Return value from validateArgumentName(String) for when the string is invalid. It might not be a valid "pattern identifier", or it have only ASCII digits but there is a leading zero or the number is too large.

Constant Value: -2

public static final double NO_NUMERIC_VALUE

Special value that is returned by getNumericValue(Part) when no numeric value is defined for a part.

Constant Value: -1.23456789E8

Public Constructors

public MessagePattern ()

Constructs an empty MessagePattern with default ApostropheMode.

public MessagePattern (MessagePattern.ApostropheMode mode)

Constructs an empty MessagePattern.

Parameters
mode Explicit ApostropheMode.

public MessagePattern (String pattern)

Constructs a MessagePattern with default ApostropheMode and parses the MessageFormat pattern string.

Parameters
pattern a MessageFormat pattern string
Throws
IllegalArgumentException for syntax errors in the pattern string
IndexOutOfBoundsException if certain limits are exceeded (e.g., argument number too high, argument name too long, etc.)
NumberFormatException if a number could not be parsed

Public Methods

public String autoQuoteApostropheDeep ()

Returns a version of the parsed pattern string where each ASCII apostrophe is doubled (escaped) if it is not already, and if it is not interpreted as quoting syntax.

For example, this turns "I don't '{know}' {gender,select,female{h''er}other{h'im}}." into "I don''t '{know}' {gender,select,female{h''er}other{h''im}}."

Returns
  • the deep-auto-quoted version of the parsed pattern string.

public void clear ()

Clears this MessagePattern. countParts() will return 0.

public void clearPatternAndSetApostropheMode (MessagePattern.ApostropheMode mode)

Clears this MessagePattern and sets the ApostropheMode. countParts() will return 0.

Parameters
mode The new ApostropheMode.

public Object clone ()

Creates and returns a copy of this object.

Returns
  • a copy of this object (or itself if frozen).

public MessagePattern cloneAsThawed ()

Creates and returns an unfrozen copy of this object.

Returns
  • a copy of this object.

public int countParts ()

Returns the number of "parts" created by parsing the pattern string. Returns 0 if no pattern has been parsed or clear() was called.

Returns
  • the number of pattern parts.

public boolean equals (Object other)

Compares this instance with the specified object and indicates if they are equal. In order to be equal, o must represent the same object as this instance using a class-specific comparison. The general contract is that this comparison should be reflexive, symmetric, and transitive. Also, no object reference other than null is equal to null.

The default implementation returns true only if this == o. See Writing a correct equals method if you intend implementing your own equals method.

The general contract for the equals and hashCode() methods is that if equals returns true for any two objects, then hashCode() must return the same value for these objects. This means that subclasses of Object usually override either both methods or neither of them.

Parameters
other another object to compare with.
Returns
  • true if this object is equivalent to the other one.

public MessagePattern freeze ()

Freezes this object, making it immutable and thread-safe.

Returns
  • this

public MessagePattern.ApostropheMode getApostropheMode ()

Returns
  • this instance's ApostropheMode.

public int getLimitPartIndex (int start)

Returns the index of the ARG|MSG_LIMIT part corresponding to the ARG|MSG_START at start.

Parameters
start The index of some Part data (0..countParts()-1); this Part should be of Type ARG_START or MSG_START.
Returns
  • The first i>start where getPart(i).getType()==ARG|MSG_LIMIT at the same nesting level, or start itself if getPartType(msgStart)!=ARG|MSG_START.
Throws
IndexOutOfBoundsException if start is outside the (0..countParts()-1) range

public double getNumericValue (MessagePattern.Part part)

Returns the numeric value associated with an ARG_INT or ARG_DOUBLE.

Parameters
part a part of this MessagePattern.
Returns
  • the part's numeric value, or NO_NUMERIC_VALUE if this is not a numeric part.

public MessagePattern.Part getPart (int i)

Gets the i-th pattern "part".

Parameters
i The index of the Part data. (0..countParts()-1)
Returns
  • the i-th pattern "part".
Throws
IndexOutOfBoundsException if i is outside the (0..countParts()-1) range

public MessagePattern.Part.Type getPartType (int i)

Returns the Part.Type of the i-th pattern "part". Convenience method for getPart(i).getType().

Parameters
i The index of the Part data. (0..countParts()-1)
Returns
  • The Part.Type of the i-th Part.
Throws
IndexOutOfBoundsException if i is outside the (0..countParts()-1) range

public int getPatternIndex (int partIndex)

Returns the pattern index of the specified pattern "part". Convenience method for getPart(partIndex).getIndex().

Parameters
partIndex The index of the Part data. (0..countParts()-1)
Returns
  • The pattern index of this Part.
Throws
IndexOutOfBoundsException if partIndex is outside the (0..countParts()-1) range

public String getPatternString ()

Returns
  • the parsed pattern string (null if none was parsed).

public double getPluralOffset (int pluralStart)

Returns the "offset:" value of a PluralFormat argument, or 0 if none is specified.

Parameters
pluralStart the index of the first PluralFormat argument style part. (0..countParts()-1)
Returns
  • the "offset:" value.
Throws
IndexOutOfBoundsException if pluralStart is outside the (0..countParts()-1) range

public String getSubstring (MessagePattern.Part part)

Returns the substring of the pattern string indicated by the Part. Convenience method for getPatternString().substring(part.getIndex(), part.getLimit()).

Parameters
part a part of this MessagePattern.
Returns
  • the substring associated with part.

public boolean hasNamedArguments ()

Does the parsed pattern have named arguments like {first_name}?

Returns
  • true if the parsed pattern has at least one named argument.

public boolean hasNumberedArguments ()

Does the parsed pattern have numbered arguments like {2}?

Returns
  • true if the parsed pattern has at least one numbered argument.

public int hashCode ()

Returns an integer hash code for this object. By contract, any two objects for which equals(Object) returns true must return the same hash code value. This means that subclasses of Object usually override both methods or neither method.

Note that hash values must not change over time unless information used in equals comparisons also changes.

See Writing a correct hashCode method if you intend implementing your own hashCode method.

Returns
  • this object's hash code.

public boolean isFrozen ()

Determines whether this object is frozen (immutable) or not.

Returns
  • true if this object is frozen.

public MessagePattern parse (String pattern)

Parses a MessageFormat pattern string.

Parameters
pattern a MessageFormat pattern string
Returns
  • this
Throws
IllegalArgumentException for syntax errors in the pattern string
IndexOutOfBoundsException if certain limits are exceeded (e.g., argument number too high, argument name too long, etc.)
NumberFormatException if a number could not be parsed

public MessagePattern parseChoiceStyle (String pattern)

Parses a ChoiceFormat pattern string.

Parameters
pattern a ChoiceFormat pattern string
Returns
  • this
Throws
IllegalArgumentException for syntax errors in the pattern string
IndexOutOfBoundsException if certain limits are exceeded (e.g., argument number too high, argument name too long, etc.)
NumberFormatException if a number could not be parsed

public MessagePattern parsePluralStyle (String pattern)

Parses a PluralFormat pattern string.

Parameters
pattern a PluralFormat pattern string
Returns
  • this
Throws
IllegalArgumentException for syntax errors in the pattern string
IndexOutOfBoundsException if certain limits are exceeded (e.g., argument number too high, argument name too long, etc.)
NumberFormatException if a number could not be parsed

public MessagePattern parseSelectStyle (String pattern)

Parses a SelectFormat pattern string.

Parameters
pattern a SelectFormat pattern string
Returns
  • this
Throws
IllegalArgumentException for syntax errors in the pattern string
IndexOutOfBoundsException if certain limits are exceeded (e.g., argument number too high, argument name too long, etc.)
NumberFormatException if a number could not be parsed

public boolean partSubstringMatches (MessagePattern.Part part, String s)

Compares the part's substring with the input string s.

Parameters
part a part of this MessagePattern.
s a string.
Returns
  • true if getSubstring(part).equals(s).

public String toString ()

Returns a string containing a concise, human-readable description of this object. Subclasses are encouraged to override this method and provide an implementation that takes into account the object's type and data. The default implementation is equivalent to the following expression:

   getClass().getName() + '@' + Integer.toHexString(hashCode())

See Writing a useful toString method if you intend implementing your own toString method.

Returns
  • a printable representation of this object.

public static int validateArgumentName (String name)

Validates and parses an argument name or argument number string. An argument name must be a "pattern identifier", that is, it must contain no Unicode Pattern_Syntax or Pattern_White_Space characters. If it only contains ASCII digits, then it must be a small integer with no leading zero.

Parameters
name Input string.
Returns
  • >=0 if the name is a valid number, ARG_NAME_NOT_NUMBER (-1) if it is a "pattern identifier" but not all ASCII digits, ARG_NAME_NOT_VALID (-2) if it is neither.