jpayne@69: // © 2016 and later: Unicode, Inc. and others. jpayne@69: // License & terms of use: http://www.unicode.org/copyright.html jpayne@69: /* jpayne@69: ******************************************************************************* jpayne@69: * Copyright (C) 2011-2013, International Business Machines jpayne@69: * Corporation and others. All Rights Reserved. jpayne@69: ******************************************************************************* jpayne@69: * file name: messagepattern.h jpayne@69: * encoding: UTF-8 jpayne@69: * tab size: 8 (not used) jpayne@69: * indentation:4 jpayne@69: * jpayne@69: * created on: 2011mar14 jpayne@69: * created by: Markus W. Scherer jpayne@69: */ jpayne@69: jpayne@69: #ifndef __MESSAGEPATTERN_H__ jpayne@69: #define __MESSAGEPATTERN_H__ jpayne@69: jpayne@69: /** jpayne@69: * \file jpayne@69: * \brief C++ API: MessagePattern class: Parses and represents ICU MessageFormat patterns. jpayne@69: */ jpayne@69: jpayne@69: #include "unicode/utypes.h" jpayne@69: jpayne@69: #if U_SHOW_CPLUSPLUS_API jpayne@69: jpayne@69: #if !UCONFIG_NO_FORMATTING jpayne@69: jpayne@69: #include "unicode/parseerr.h" jpayne@69: #include "unicode/unistr.h" jpayne@69: jpayne@69: /** jpayne@69: * Mode for when an apostrophe starts quoted literal text for MessageFormat output. jpayne@69: * The default is DOUBLE_OPTIONAL unless overridden via uconfig.h jpayne@69: * (UCONFIG_MSGPAT_DEFAULT_APOSTROPHE_MODE). jpayne@69: *
jpayne@69: * A pair of adjacent apostrophes always results in a single apostrophe in the output, jpayne@69: * even when the pair is between two single, text-quoting apostrophes. jpayne@69: *
jpayne@69: * The following table shows examples of desired MessageFormat.format() output jpayne@69: * with the pattern strings that yield that output. jpayne@69: *
jpayne@69: *
Desired output | jpayne@69: *DOUBLE_OPTIONAL | jpayne@69: *DOUBLE_REQUIRED | jpayne@69: *
---|---|---|
I see {many} | jpayne@69: *I see '{many}' | jpayne@69: *(same) | jpayne@69: *
I said {'Wow!'} | jpayne@69: *I said '{''Wow!''}' | jpayne@69: *(same) | jpayne@69: *
I don't know | jpayne@69: *I don't know OR I don''t know |
jpayne@69: * I don''t know | jpayne@69: *
jpayne@69: * This is the default behavior starting with ICU 4.8. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: UMSGPAT_APOS_DOUBLE_OPTIONAL, jpayne@69: /** jpayne@69: * A literal apostrophe must be represented by jpayne@69: * a double apostrophe pattern character. jpayne@69: * A single apostrophe always starts quoted literal text. jpayne@69: *
jpayne@69: * This is the behavior of ICU 4.6 and earlier, and of the JDK. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: UMSGPAT_APOS_DOUBLE_REQUIRED jpayne@69: }; jpayne@69: /** jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: typedef enum UMessagePatternApostropheMode UMessagePatternApostropheMode; jpayne@69: jpayne@69: /** jpayne@69: * MessagePattern::Part type constants. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: enum UMessagePatternPartType { jpayne@69: /** jpayne@69: * Start of a message pattern (main or nested). jpayne@69: * The length is 0 for the top-level message jpayne@69: * and for a choice argument sub-message, otherwise 1 for the '{'. jpayne@69: * The value indicates the nesting level, starting with 0 for the main message. jpayne@69: *
jpayne@69: * There is always a later MSG_LIMIT part. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: UMSGPAT_PART_TYPE_MSG_START, jpayne@69: /** jpayne@69: * End of a message pattern (main or nested). jpayne@69: * The length is 0 for the top-level message and jpayne@69: * the last sub-message of a choice argument, jpayne@69: * otherwise 1 for the '}' or (in a choice argument style) the '|'. jpayne@69: * The value indicates the nesting level, starting with 0 for the main message. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: UMSGPAT_PART_TYPE_MSG_LIMIT, jpayne@69: /** jpayne@69: * Indicates a substring of the pattern string which is to be skipped when formatting. jpayne@69: * For example, an apostrophe that begins or ends quoted text jpayne@69: * would be indicated with such a part. jpayne@69: * The value is undefined and currently always 0. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: UMSGPAT_PART_TYPE_SKIP_SYNTAX, jpayne@69: /** jpayne@69: * Indicates that a syntax character needs to be inserted for auto-quoting. jpayne@69: * The length is 0. jpayne@69: * The value is the character code of the insertion character. (U+0027=APOSTROPHE) jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: UMSGPAT_PART_TYPE_INSERT_CHAR, jpayne@69: /** jpayne@69: * Indicates a syntactic (non-escaped) # symbol in a plural variant. jpayne@69: * When formatting, replace this part's substring with the jpayne@69: * (value-offset) for the plural argument value. jpayne@69: * The value is undefined and currently always 0. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: UMSGPAT_PART_TYPE_REPLACE_NUMBER, jpayne@69: /** jpayne@69: * Start of an argument. jpayne@69: * The length is 1 for the '{'. jpayne@69: * The value is the ordinal value of the ArgType. Use getArgType(). jpayne@69: *
jpayne@69: * This part is followed by either an ARG_NUMBER or ARG_NAME, jpayne@69: * followed by optional argument sub-parts (see UMessagePatternArgType constants) jpayne@69: * and finally an ARG_LIMIT part. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: UMSGPAT_PART_TYPE_ARG_START, jpayne@69: /** jpayne@69: * End of an argument. jpayne@69: * The length is 1 for the '}'. jpayne@69: * The value is the ordinal value of the ArgType. Use getArgType(). jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: UMSGPAT_PART_TYPE_ARG_LIMIT, jpayne@69: /** jpayne@69: * The argument number, provided by the value. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: UMSGPAT_PART_TYPE_ARG_NUMBER, jpayne@69: /** jpayne@69: * The argument name. jpayne@69: * The value is undefined and currently always 0. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: UMSGPAT_PART_TYPE_ARG_NAME, jpayne@69: /** jpayne@69: * The argument type. jpayne@69: * The value is undefined and currently always 0. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: UMSGPAT_PART_TYPE_ARG_TYPE, jpayne@69: /** jpayne@69: * The argument style text. jpayne@69: * The value is undefined and currently always 0. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: UMSGPAT_PART_TYPE_ARG_STYLE, jpayne@69: /** jpayne@69: * A selector substring in a "complex" argument style. jpayne@69: * The value is undefined and currently always 0. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: UMSGPAT_PART_TYPE_ARG_SELECTOR, jpayne@69: /** jpayne@69: * An integer value, for example the offset or an explicit selector value jpayne@69: * in a PluralFormat style. jpayne@69: * The part value is the integer value. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: UMSGPAT_PART_TYPE_ARG_INT, jpayne@69: /** jpayne@69: * A numeric value, for example the offset or an explicit selector value jpayne@69: * in a PluralFormat style. jpayne@69: * The part value is an index into an internal array of numeric values; jpayne@69: * use getNumericValue(). jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: UMSGPAT_PART_TYPE_ARG_DOUBLE jpayne@69: }; jpayne@69: /** jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: typedef enum UMessagePatternPartType UMessagePatternPartType; jpayne@69: jpayne@69: /** jpayne@69: * Argument type constants. jpayne@69: * Returned by Part.getArgType() for ARG_START and ARG_LIMIT parts. jpayne@69: * jpayne@69: * Messages nested inside an argument are each delimited by MSG_START and MSG_LIMIT, jpayne@69: * with a nesting level one greater than the surrounding message. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: enum UMessagePatternArgType { jpayne@69: /** jpayne@69: * The argument has no specified type. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: UMSGPAT_ARG_TYPE_NONE, jpayne@69: /** jpayne@69: * The argument has a "simple" type which is provided by the ARG_TYPE part. jpayne@69: * An ARG_STYLE part might follow that. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: UMSGPAT_ARG_TYPE_SIMPLE, jpayne@69: /** jpayne@69: * The argument is a ChoiceFormat with one or more jpayne@69: * ((ARG_INT | ARG_DOUBLE), ARG_SELECTOR, message) tuples. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: UMSGPAT_ARG_TYPE_CHOICE, jpayne@69: /** jpayne@69: * The argument is a cardinal-number PluralFormat with an optional ARG_INT or ARG_DOUBLE offset jpayne@69: * (e.g., offset:1) jpayne@69: * and one or more (ARG_SELECTOR [explicit-value] message) tuples. jpayne@69: * If the selector has an explicit value (e.g., =2), then jpayne@69: * that value is provided by the ARG_INT or ARG_DOUBLE part preceding the message. jpayne@69: * Otherwise the message immediately follows the ARG_SELECTOR. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: UMSGPAT_ARG_TYPE_PLURAL, jpayne@69: /** jpayne@69: * The argument is a SelectFormat with one or more (ARG_SELECTOR, message) pairs. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: UMSGPAT_ARG_TYPE_SELECT, jpayne@69: /** jpayne@69: * The argument is an ordinal-number PluralFormat jpayne@69: * with the same style parts sequence and semantics as UMSGPAT_ARG_TYPE_PLURAL. jpayne@69: * @stable ICU 50 jpayne@69: */ jpayne@69: UMSGPAT_ARG_TYPE_SELECTORDINAL jpayne@69: }; jpayne@69: /** jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: typedef enum UMessagePatternArgType UMessagePatternArgType; jpayne@69: jpayne@69: /** jpayne@69: * \def UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE jpayne@69: * Returns TRUE if the argument type has a plural style part sequence and semantics, jpayne@69: * for example UMSGPAT_ARG_TYPE_PLURAL and UMSGPAT_ARG_TYPE_SELECTORDINAL. jpayne@69: * @stable ICU 50 jpayne@69: */ jpayne@69: #define UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(argType) \ jpayne@69: ((argType)==UMSGPAT_ARG_TYPE_PLURAL || (argType)==UMSGPAT_ARG_TYPE_SELECTORDINAL) jpayne@69: jpayne@69: enum { jpayne@69: /** jpayne@69: * Return value from MessagePattern.validateArgumentName() for when jpayne@69: * the string is a valid "pattern identifier" but not a number. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: UMSGPAT_ARG_NAME_NOT_NUMBER=-1, jpayne@69: jpayne@69: /** jpayne@69: * Return value from MessagePattern.validateArgumentName() for when jpayne@69: * the string is invalid. jpayne@69: * It might not be a valid "pattern identifier", jpayne@69: * or it have only ASCII digits but there is a leading zero or the number is too large. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: UMSGPAT_ARG_NAME_NOT_VALID=-2 jpayne@69: }; jpayne@69: jpayne@69: /** jpayne@69: * Special value that is returned by getNumericValue(Part) when no jpayne@69: * numeric value is defined for a part. jpayne@69: * @see MessagePattern.getNumericValue() jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: #define UMSGPAT_NO_NUMERIC_VALUE ((double)(-123456789)) jpayne@69: jpayne@69: U_NAMESPACE_BEGIN jpayne@69: jpayne@69: class MessagePatternDoubleList; jpayne@69: class MessagePatternPartsList; jpayne@69: jpayne@69: /** jpayne@69: * Parses and represents ICU MessageFormat patterns. jpayne@69: * Also handles patterns for ChoiceFormat, PluralFormat and SelectFormat. jpayne@69: * Used in the implementations of those classes as well as in tools jpayne@69: * for message validation, translation and format conversion. jpayne@69: *
jpayne@69: * The parser handles all syntax relevant for identifying message arguments. jpayne@69: * This includes "complex" arguments whose style strings contain jpayne@69: * nested MessageFormat pattern substrings. jpayne@69: * For "simple" arguments (with no nested MessageFormat pattern substrings), jpayne@69: * the argument style is not parsed any further. jpayne@69: *
jpayne@69: * The parser handles named and numbered message arguments and allows both in one message. jpayne@69: *
jpayne@69: * Once a pattern has been parsed successfully, iterate through the parsed data jpayne@69: * with countParts(), getPart() and related methods. jpayne@69: *
jpayne@69: * The data logically represents a parse tree, but is stored and accessed jpayne@69: * as a list of "parts" for fast and simple parsing and to minimize object allocations. jpayne@69: * Arguments and nested messages are best handled via recursion. jpayne@69: * For every _START "part", MessagePattern.getLimitPartIndex() efficiently returns jpayne@69: * the index of the corresponding _LIMIT "part". jpayne@69: *
jpayne@69: * List of "parts": jpayne@69: *
jpayne@69: * message = MSG_START (SKIP_SYNTAX | INSERT_CHAR | REPLACE_NUMBER | argument)* MSG_LIMIT jpayne@69: * argument = noneArg | simpleArg | complexArg jpayne@69: * complexArg = choiceArg | pluralArg | selectArg jpayne@69: * jpayne@69: * noneArg = ARG_START.NONE (ARG_NAME | ARG_NUMBER) ARG_LIMIT.NONE jpayne@69: * simpleArg = ARG_START.SIMPLE (ARG_NAME | ARG_NUMBER) ARG_TYPE [ARG_STYLE] ARG_LIMIT.SIMPLE jpayne@69: * choiceArg = ARG_START.CHOICE (ARG_NAME | ARG_NUMBER) choiceStyle ARG_LIMIT.CHOICE jpayne@69: * pluralArg = ARG_START.PLURAL (ARG_NAME | ARG_NUMBER) pluralStyle ARG_LIMIT.PLURAL jpayne@69: * selectArg = ARG_START.SELECT (ARG_NAME | ARG_NUMBER) selectStyle ARG_LIMIT.SELECT jpayne@69: * jpayne@69: * choiceStyle = ((ARG_INT | ARG_DOUBLE) ARG_SELECTOR message)+ jpayne@69: * pluralStyle = [ARG_INT | ARG_DOUBLE] (ARG_SELECTOR [ARG_INT | ARG_DOUBLE] message)+ jpayne@69: * selectStyle = (ARG_SELECTOR message)+ jpayne@69: *jpayne@69: *
ARG_START.CHOICE
stands for an ARG_START Part with ArgType CHOICE.
jpayne@69: * jpayne@69: * This class is not intended for public subclassing. jpayne@69: * jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: class U_COMMON_API MessagePattern : public UObject { jpayne@69: public: jpayne@69: /** jpayne@69: * Constructs an empty MessagePattern with default UMessagePatternApostropheMode. jpayne@69: * @param errorCode Standard ICU error code. Its input value must jpayne@69: * pass the U_SUCCESS() test, or else the function returns jpayne@69: * immediately. Check for U_FAILURE() on output or use with jpayne@69: * function chaining. (See User Guide for details.) jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: MessagePattern(UErrorCode &errorCode); jpayne@69: jpayne@69: /** jpayne@69: * Constructs an empty MessagePattern. jpayne@69: * @param mode Explicit UMessagePatternApostropheMode. jpayne@69: * @param errorCode Standard ICU error code. Its input value must jpayne@69: * pass the U_SUCCESS() test, or else the function returns jpayne@69: * immediately. Check for U_FAILURE() on output or use with jpayne@69: * function chaining. (See User Guide for details.) jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: MessagePattern(UMessagePatternApostropheMode mode, UErrorCode &errorCode); jpayne@69: jpayne@69: /** jpayne@69: * Constructs a MessagePattern with default UMessagePatternApostropheMode and jpayne@69: * parses the MessageFormat pattern string. jpayne@69: * @param pattern a MessageFormat pattern string jpayne@69: * @param parseError Struct to receive information on the position jpayne@69: * of an error within the pattern. jpayne@69: * Can be NULL. jpayne@69: * @param errorCode Standard ICU error code. Its input value must jpayne@69: * pass the U_SUCCESS() test, or else the function returns jpayne@69: * immediately. Check for U_FAILURE() on output or use with jpayne@69: * function chaining. (See User Guide for details.) jpayne@69: * TODO: turn @throws into UErrorCode specifics? jpayne@69: * @throws IllegalArgumentException for syntax errors in the pattern string jpayne@69: * @throws IndexOutOfBoundsException if certain limits are exceeded jpayne@69: * (e.g., argument number too high, argument name too long, etc.) jpayne@69: * @throws NumberFormatException if a number could not be parsed jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: MessagePattern(const UnicodeString &pattern, UParseError *parseError, UErrorCode &errorCode); jpayne@69: jpayne@69: /** jpayne@69: * Copy constructor. jpayne@69: * @param other Object to copy. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: MessagePattern(const MessagePattern &other); jpayne@69: jpayne@69: /** jpayne@69: * Assignment operator. jpayne@69: * @param other Object to copy. jpayne@69: * @return *this=other jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: MessagePattern &operator=(const MessagePattern &other); jpayne@69: jpayne@69: /** jpayne@69: * Destructor. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: virtual ~MessagePattern(); jpayne@69: jpayne@69: /** jpayne@69: * Parses a MessageFormat pattern string. jpayne@69: * @param pattern a MessageFormat pattern string jpayne@69: * @param parseError Struct to receive information on the position jpayne@69: * of an error within the pattern. jpayne@69: * Can be NULL. jpayne@69: * @param errorCode Standard ICU error code. Its input value must jpayne@69: * pass the U_SUCCESS() test, or else the function returns jpayne@69: * immediately. Check for U_FAILURE() on output or use with jpayne@69: * function chaining. (See User Guide for details.) jpayne@69: * @return *this jpayne@69: * @throws IllegalArgumentException for syntax errors in the pattern string jpayne@69: * @throws IndexOutOfBoundsException if certain limits are exceeded jpayne@69: * (e.g., argument number too high, argument name too long, etc.) jpayne@69: * @throws NumberFormatException if a number could not be parsed jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: MessagePattern &parse(const UnicodeString &pattern, jpayne@69: UParseError *parseError, UErrorCode &errorCode); jpayne@69: jpayne@69: /** jpayne@69: * Parses a ChoiceFormat pattern string. jpayne@69: * @param pattern a ChoiceFormat pattern string jpayne@69: * @param parseError Struct to receive information on the position jpayne@69: * of an error within the pattern. jpayne@69: * Can be NULL. jpayne@69: * @param errorCode Standard ICU error code. Its input value must jpayne@69: * pass the U_SUCCESS() test, or else the function returns jpayne@69: * immediately. Check for U_FAILURE() on output or use with jpayne@69: * function chaining. (See User Guide for details.) jpayne@69: * @return *this jpayne@69: * @throws IllegalArgumentException for syntax errors in the pattern string jpayne@69: * @throws IndexOutOfBoundsException if certain limits are exceeded jpayne@69: * (e.g., argument number too high, argument name too long, etc.) jpayne@69: * @throws NumberFormatException if a number could not be parsed jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: MessagePattern &parseChoiceStyle(const UnicodeString &pattern, jpayne@69: UParseError *parseError, UErrorCode &errorCode); jpayne@69: jpayne@69: /** jpayne@69: * Parses a PluralFormat pattern string. jpayne@69: * @param pattern a PluralFormat pattern string jpayne@69: * @param parseError Struct to receive information on the position jpayne@69: * of an error within the pattern. jpayne@69: * Can be NULL. jpayne@69: * @param errorCode Standard ICU error code. Its input value must jpayne@69: * pass the U_SUCCESS() test, or else the function returns jpayne@69: * immediately. Check for U_FAILURE() on output or use with jpayne@69: * function chaining. (See User Guide for details.) jpayne@69: * @return *this jpayne@69: * @throws IllegalArgumentException for syntax errors in the pattern string jpayne@69: * @throws IndexOutOfBoundsException if certain limits are exceeded jpayne@69: * (e.g., argument number too high, argument name too long, etc.) jpayne@69: * @throws NumberFormatException if a number could not be parsed jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: MessagePattern &parsePluralStyle(const UnicodeString &pattern, jpayne@69: UParseError *parseError, UErrorCode &errorCode); jpayne@69: jpayne@69: /** jpayne@69: * Parses a SelectFormat pattern string. jpayne@69: * @param pattern a SelectFormat pattern string jpayne@69: * @param parseError Struct to receive information on the position jpayne@69: * of an error within the pattern. jpayne@69: * Can be NULL. jpayne@69: * @param errorCode Standard ICU error code. Its input value must jpayne@69: * pass the U_SUCCESS() test, or else the function returns jpayne@69: * immediately. Check for U_FAILURE() on output or use with jpayne@69: * function chaining. (See User Guide for details.) jpayne@69: * @return *this jpayne@69: * @throws IllegalArgumentException for syntax errors in the pattern string jpayne@69: * @throws IndexOutOfBoundsException if certain limits are exceeded jpayne@69: * (e.g., argument number too high, argument name too long, etc.) jpayne@69: * @throws NumberFormatException if a number could not be parsed jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: MessagePattern &parseSelectStyle(const UnicodeString &pattern, jpayne@69: UParseError *parseError, UErrorCode &errorCode); jpayne@69: jpayne@69: /** jpayne@69: * Clears this MessagePattern. jpayne@69: * countParts() will return 0. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: void clear(); jpayne@69: jpayne@69: /** jpayne@69: * Clears this MessagePattern and sets the UMessagePatternApostropheMode. jpayne@69: * countParts() will return 0. jpayne@69: * @param mode The new UMessagePatternApostropheMode. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: void clearPatternAndSetApostropheMode(UMessagePatternApostropheMode mode) { jpayne@69: clear(); jpayne@69: aposMode=mode; jpayne@69: } jpayne@69: jpayne@69: /** jpayne@69: * @param other another object to compare with. jpayne@69: * @return TRUE if this object is equivalent to the other one. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: UBool operator==(const MessagePattern &other) const; jpayne@69: jpayne@69: /** jpayne@69: * @param other another object to compare with. jpayne@69: * @return FALSE if this object is equivalent to the other one. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: inline UBool operator!=(const MessagePattern &other) const { jpayne@69: return !operator==(other); jpayne@69: } jpayne@69: jpayne@69: /** jpayne@69: * @return A hash code for this object. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: int32_t hashCode() const; jpayne@69: jpayne@69: /** jpayne@69: * @return this instance's UMessagePatternApostropheMode. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: UMessagePatternApostropheMode getApostropheMode() const { jpayne@69: return aposMode; jpayne@69: } jpayne@69: jpayne@69: // Java has package-private jdkAposMode() here. jpayne@69: // In C++, this is declared in the MessageImpl class. jpayne@69: jpayne@69: /** jpayne@69: * @return the parsed pattern string (null if none was parsed). jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: const UnicodeString &getPatternString() const { jpayne@69: return msg; jpayne@69: } jpayne@69: jpayne@69: /** jpayne@69: * Does the parsed pattern have named arguments like {first_name}? jpayne@69: * @return TRUE if the parsed pattern has at least one named argument. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: UBool hasNamedArguments() const { jpayne@69: return hasArgNames; jpayne@69: } jpayne@69: jpayne@69: /** jpayne@69: * Does the parsed pattern have numbered arguments like {2}? jpayne@69: * @return TRUE if the parsed pattern has at least one numbered argument. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: UBool hasNumberedArguments() const { jpayne@69: return hasArgNumbers; jpayne@69: } jpayne@69: jpayne@69: /** jpayne@69: * Validates and parses an argument name or argument number string. jpayne@69: * An argument name must be a "pattern identifier", that is, it must contain jpayne@69: * no Unicode Pattern_Syntax or Pattern_White_Space characters. jpayne@69: * If it only contains ASCII digits, then it must be a small integer with no leading zero. jpayne@69: * @param name Input string. jpayne@69: * @return >=0 if the name is a valid number, jpayne@69: * ARG_NAME_NOT_NUMBER (-1) if it is a "pattern identifier" but not all ASCII digits, jpayne@69: * ARG_NAME_NOT_VALID (-2) if it is neither. jpayne@69: * @stable ICU 4.8 jpayne@69: */ jpayne@69: static int32_t validateArgumentName(const UnicodeString &name); jpayne@69: jpayne@69: /** jpayne@69: * Returns a version of the parsed pattern string where each ASCII apostrophe jpayne@69: * is doubled (escaped) if it is not already, and if it is not interpreted as quoting syntax. jpayne@69: *
jpayne@69: * For example, this turns "I don't '{know}' {gender,select,female{h''er}other{h'im}}."
jpayne@69: * into "I don''t '{know}' {gender,select,female{h''er}other{h''im}}."
jpayne@69: * @return the deep-auto-quoted version of the parsed pattern string.
jpayne@69: * @see MessageFormat.autoQuoteApostrophe()
jpayne@69: * @stable ICU 4.8
jpayne@69: */
jpayne@69: UnicodeString autoQuoteApostropheDeep() const;
jpayne@69:
jpayne@69: class Part;
jpayne@69:
jpayne@69: /**
jpayne@69: * Returns the number of "parts" created by parsing the pattern string.
jpayne@69: * Returns 0 if no pattern has been parsed or clear() was called.
jpayne@69: * @return the number of pattern parts.
jpayne@69: * @stable ICU 4.8
jpayne@69: */
jpayne@69: int32_t countParts() const {
jpayne@69: return partsLength;
jpayne@69: }
jpayne@69:
jpayne@69: /**
jpayne@69: * Gets the i-th pattern "part".
jpayne@69: * @param i The index of the Part data. (0..countParts()-1)
jpayne@69: * @return the i-th pattern "part".
jpayne@69: * @stable ICU 4.8
jpayne@69: */
jpayne@69: const Part &getPart(int32_t i) const {
jpayne@69: return parts[i];
jpayne@69: }
jpayne@69:
jpayne@69: /**
jpayne@69: * Returns the UMessagePatternPartType of the i-th pattern "part".
jpayne@69: * Convenience method for getPart(i).getType().
jpayne@69: * @param i The index of the Part data. (0..countParts()-1)
jpayne@69: * @return The UMessagePatternPartType of the i-th Part.
jpayne@69: * @stable ICU 4.8
jpayne@69: */
jpayne@69: UMessagePatternPartType getPartType(int32_t i) const {
jpayne@69: return getPart(i).type;
jpayne@69: }
jpayne@69:
jpayne@69: /**
jpayne@69: * Returns the pattern index of the specified pattern "part".
jpayne@69: * Convenience method for getPart(partIndex).getIndex().
jpayne@69: * @param partIndex The index of the Part data. (0..countParts()-1)
jpayne@69: * @return The pattern index of this Part.
jpayne@69: * @stable ICU 4.8
jpayne@69: */
jpayne@69: int32_t getPatternIndex(int32_t partIndex) const {
jpayne@69: return getPart(partIndex).index;
jpayne@69: }
jpayne@69:
jpayne@69: /**
jpayne@69: * Returns the substring of the pattern string indicated by the Part.
jpayne@69: * Convenience method for getPatternString().substring(part.getIndex(), part.getLimit()).
jpayne@69: * @param part a part of this MessagePattern.
jpayne@69: * @return the substring associated with part.
jpayne@69: * @stable ICU 4.8
jpayne@69: */
jpayne@69: UnicodeString getSubstring(const Part &part) const {
jpayne@69: return msg.tempSubString(part.index, part.length);
jpayne@69: }
jpayne@69:
jpayne@69: /**
jpayne@69: * Compares the part's substring with the input string s.
jpayne@69: * @param part a part of this MessagePattern.
jpayne@69: * @param s a string.
jpayne@69: * @return TRUE if getSubstring(part).equals(s).
jpayne@69: * @stable ICU 4.8
jpayne@69: */
jpayne@69: UBool partSubstringMatches(const Part &part, const UnicodeString &s) const {
jpayne@69: return 0==msg.compare(part.index, part.length, s);
jpayne@69: }
jpayne@69:
jpayne@69: /**
jpayne@69: * Returns the numeric value associated with an ARG_INT or ARG_DOUBLE.
jpayne@69: * @param part a part of this MessagePattern.
jpayne@69: * @return the part's numeric value, or UMSGPAT_NO_NUMERIC_VALUE if this is not a numeric part.
jpayne@69: * @stable ICU 4.8
jpayne@69: */
jpayne@69: double getNumericValue(const Part &part) const;
jpayne@69:
jpayne@69: /**
jpayne@69: * Returns the "offset:" value of a PluralFormat argument, or 0 if none is specified.
jpayne@69: * @param pluralStart the index of the first PluralFormat argument style part. (0..countParts()-1)
jpayne@69: * @return the "offset:" value.
jpayne@69: * @stable ICU 4.8
jpayne@69: */
jpayne@69: double getPluralOffset(int32_t pluralStart) const;
jpayne@69:
jpayne@69: /**
jpayne@69: * Returns the index of the ARG|MSG_LIMIT part corresponding to the ARG|MSG_START at start.
jpayne@69: * @param start The index of some Part data (0..countParts()-1);
jpayne@69: * this Part should be of Type ARG_START or MSG_START.
jpayne@69: * @return The first i>start where getPart(i).getType()==ARG|MSG_LIMIT at the same nesting level,
jpayne@69: * or start itself if getPartType(msgStart)!=ARG|MSG_START.
jpayne@69: * @stable ICU 4.8
jpayne@69: */
jpayne@69: int32_t getLimitPartIndex(int32_t start) const {
jpayne@69: int32_t limit=getPart(start).limitPartIndex;
jpayne@69: if(limit