• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // © 2017 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 
4 #include "unicode/utypes.h"
5 
6 #if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT
7 #ifndef __NUMBER_PATTERNSTRING_H__
8 #define __NUMBER_PATTERNSTRING_H__
9 
10 
11 #include <cstdint>
12 #include "unicode/unum.h"
13 #include "unicode/unistr.h"
14 #include "number_types.h"
15 #include "number_decimalquantity.h"
16 #include "number_decimfmtprops.h"
17 #include "number_affixutils.h"
18 
19 U_NAMESPACE_BEGIN namespace number {
20 namespace impl {
21 
22 // Forward declaration
23 class PatternParser;
24 
25 // Exported as U_I18N_API because it is a public member field of exported ParsedSubpatternInfo
26 struct U_I18N_API Endpoints {
27     int32_t start = 0;
28     int32_t end = 0;
29 };
30 
31 // Exported as U_I18N_API because it is a public member field of exported ParsedPatternInfo
32 struct U_I18N_API ParsedSubpatternInfo {
33     int64_t groupingSizes = 0x0000ffffffff0000L;
34     int32_t integerLeadingHashSigns = 0;
35     int32_t integerTrailingHashSigns = 0;
36     int32_t integerNumerals = 0;
37     int32_t integerAtSigns = 0;
38     int32_t integerTotal = 0; // for convenience
39     int32_t fractionNumerals = 0;
40     int32_t fractionHashSigns = 0;
41     int32_t fractionTotal = 0; // for convenience
42     bool hasDecimal = false;
43     int32_t widthExceptAffixes = 0;
44     NullableValue<UNumberFormatPadPosition> paddingLocation;
45     DecimalQuantity rounding;
46     bool exponentHasPlusSign = false;
47     int32_t exponentZeros = 0;
48     bool hasPercentSign = false;
49     bool hasPerMilleSign = false;
50     bool hasCurrencySign = false;
51     bool hasMinusSign = false;
52     bool hasPlusSign = false;
53 
54     Endpoints prefixEndpoints;
55     Endpoints suffixEndpoints;
56     Endpoints paddingEndpoints;
57 };
58 
59 // Exported as U_I18N_API because it is needed for the unit test PatternStringTest
60 struct U_I18N_API ParsedPatternInfo : public AffixPatternProvider, public UMemory {
61     UnicodeString pattern;
62     ParsedSubpatternInfo positive;
63     ParsedSubpatternInfo negative;
64 
ParsedPatternInfoParsedPatternInfo65     ParsedPatternInfo() : state(this->pattern), currentSubpattern(nullptr) {}
66 
67     ~ParsedPatternInfo() U_OVERRIDE = default;
68 
69     static int32_t getLengthFromEndpoints(const Endpoints &endpoints);
70 
71     char16_t charAt(int32_t flags, int32_t index) const U_OVERRIDE;
72 
73     int32_t length(int32_t flags) const U_OVERRIDE;
74 
75     UnicodeString getString(int32_t flags) const;
76 
77     bool positiveHasPlusSign() const U_OVERRIDE;
78 
79     bool hasNegativeSubpattern() const U_OVERRIDE;
80 
81     bool negativeHasMinusSign() const U_OVERRIDE;
82 
83     bool hasCurrencySign() const U_OVERRIDE;
84 
85     bool containsSymbolType(AffixPatternType type, UErrorCode &status) const U_OVERRIDE;
86 
87   private:
88     struct U_I18N_API ParserState {
89         const UnicodeString &pattern; // reference to the parent
90         int32_t offset = 0;
91 
ParserStateParsedPatternInfo::ParserState92         explicit ParserState(const UnicodeString &_pattern) : pattern(_pattern) {};
93 
94         UChar32 peek();
95 
96         UChar32 next();
97 
98         // TODO: We don't currently do anything with the message string.
99         // This method is here as a shell for Java compatibility.
toParseExceptionParsedPatternInfo::ParserState100         inline void toParseException(const char16_t *message) { (void)message; }
101     }
102     state;
103 
104     // NOTE: In Java, these are written as pure functions.
105     // In C++, they're written as methods.
106     // The behavior is the same.
107 
108     // Mutable transient pointer:
109     ParsedSubpatternInfo *currentSubpattern;
110 
111     // In Java, "negative == null" tells us whether or not we had a negative subpattern.
112     // In C++, we need to remember in another boolean.
113     bool fHasNegativeSubpattern = false;
114 
115     const Endpoints &getEndpoints(int32_t flags) const;
116 
117     /** Run the recursive descent parser. */
118     void consumePattern(const UnicodeString &patternString, UErrorCode &status);
119 
120     void consumeSubpattern(UErrorCode &status);
121 
122     void consumePadding(PadPosition paddingLocation, UErrorCode &status);
123 
124     void consumeAffix(Endpoints &endpoints, UErrorCode &status);
125 
126     void consumeLiteral(UErrorCode &status);
127 
128     void consumeFormat(UErrorCode &status);
129 
130     void consumeIntegerFormat(UErrorCode &status);
131 
132     void consumeFractionFormat(UErrorCode &status);
133 
134     void consumeExponent(UErrorCode &status);
135 
136     friend class PatternParser;
137 };
138 
139 class U_I18N_API PatternParser {
140   public:
141     /**
142      * Runs the recursive descent parser on the given pattern string, returning a data structure with raw information
143      * about the pattern string.
144      *
145      * <p>
146      * To obtain a more useful form of the data, consider using {@link #parseToProperties} instead.
147      *
148      * TODO: Change argument type to const char16_t* instead of UnicodeString?
149      *
150      * @param patternString
151      *            The LDML decimal format pattern (Excel-style pattern) to parse.
152      * @return The results of the parse.
153      */
154     static void
155     parseToPatternInfo(const UnicodeString& patternString, ParsedPatternInfo &patternInfo, UErrorCode &status);
156 
157     enum IgnoreRounding {
158         IGNORE_ROUNDING_NEVER = 0, IGNORE_ROUNDING_IF_CURRENCY = 1, IGNORE_ROUNDING_ALWAYS = 2
159     };
160 
161     /**
162      * Parses a pattern string into a new property bag.
163      *
164      * @param pattern
165      *            The pattern string, like "#,##0.00"
166      * @param ignoreRounding
167      *            Whether to leave out rounding information (minFrac, maxFrac, and rounding increment) when parsing the
168      *            pattern. This may be desirable if a custom rounding mode, such as CurrencyUsage, is to be used
169      *            instead.
170      * @return A property bag object.
171      * @throws IllegalArgumentException
172      *             If there is a syntax error in the pattern string.
173      */
174     static DecimalFormatProperties
175     parseToProperties(const UnicodeString& pattern, IgnoreRounding ignoreRounding, UErrorCode &status);
176 
177     /**
178      * Parses a pattern string into an existing property bag. All properties that can be encoded into a pattern string
179      * will be overwritten with either their default value or with the value coming from the pattern string. Properties
180      * that cannot be encoded into a pattern string, such as rounding mode, are not modified.
181      *
182      * @param pattern
183      *            The pattern string, like "#,##0.00"
184      * @param properties
185      *            The property bag object to overwrite.
186      * @param ignoreRounding
187      *            See {@link #parseToProperties(String pattern, int ignoreRounding)}.
188      * @throws IllegalArgumentException
189      *             If there was a syntax error in the pattern string.
190      */
191     static void parseToExistingProperties(const UnicodeString& pattern, DecimalFormatProperties& properties,
192                                           IgnoreRounding ignoreRounding, UErrorCode &status);
193 
194   private:
195     static void
196     parseToExistingPropertiesImpl(const UnicodeString& pattern, DecimalFormatProperties &properties,
197                                   IgnoreRounding ignoreRounding, UErrorCode &status);
198 
199     /** Finalizes the temporary data stored in the ParsedPatternInfo to the Properties. */
200     static void
201     patternInfoToProperties(DecimalFormatProperties &properties, ParsedPatternInfo& patternInfo,
202                             IgnoreRounding _ignoreRounding, UErrorCode &status);
203 };
204 
205 class U_I18N_API PatternStringUtils {
206   public:
207     /**
208      * Creates a pattern string from a property bag.
209      *
210      * <p>
211      * Since pattern strings support only a subset of the functionality available in a property bag, a new property bag
212      * created from the string returned by this function may not be the same as the original property bag.
213      *
214      * @param properties
215      *            The property bag to serialize.
216      * @return A pattern string approximately serializing the property bag.
217      */
218     static UnicodeString
219     propertiesToPatternString(const DecimalFormatProperties &properties, UErrorCode &status);
220 
221 
222     /**
223      * Converts a pattern between standard notation and localized notation. Localized notation means that instead of
224      * using generic placeholders in the pattern, you use the corresponding locale-specific characters instead. For
225      * example, in locale <em>fr-FR</em>, the period in the pattern "0.000" means "decimal" in standard notation (as it
226      * does in every other locale), but it means "grouping" in localized notation.
227      *
228      * <p>
229      * A greedy string-substitution strategy is used to substitute locale symbols. If two symbols are ambiguous or have
230      * the same prefix, the result is not well-defined.
231      *
232      * <p>
233      * Locale symbols are not allowed to contain the ASCII quote character.
234      *
235      * <p>
236      * This method is provided for backwards compatibility and should not be used in any new code.
237      *
238      * TODO(C++): This method is not yet implemented.
239      *
240      * @param input
241      *            The pattern to convert.
242      * @param symbols
243      *            The symbols corresponding to the localized pattern.
244      * @param toLocalized
245      *            true to convert from standard to localized notation; false to convert from localized to standard
246      *            notation.
247      * @return The pattern expressed in the other notation.
248      */
249     static UnicodeString
250     convertLocalized(UnicodeString input, DecimalFormatSymbols symbols, bool toLocalized,
251                      UErrorCode &status);
252 
253   private:
254     /** @return The number of chars inserted. */
255     static int
256     escapePaddingString(UnicodeString input, UnicodeString &output, int startIndex, UErrorCode &status);
257 };
258 
259 } // namespace impl
260 } // namespace number
261 U_NAMESPACE_END
262 
263 
264 #endif //__NUMBER_PATTERNSTRING_H__
265 
266 #endif /* #if !UCONFIG_NO_FORMATTING */
267