1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 **********************************************************************
5 * Copyright (c) 2014, International Business Machines
6 * Corporation and others. All Rights Reserved.
7 **********************************************************************
8 */
9 #include "unicode/utypes.h"
10
11 #if !UCONFIG_NO_FORMATTING
12
13 #include "unicode/scientificnumberformatter.h"
14 #include "unicode/dcfmtsym.h"
15 #include "unicode/fpositer.h"
16 #include "unicode/utf16.h"
17 #include "unicode/uniset.h"
18 #include "unicode/decimfmt.h"
19 #include "static_unicode_sets.h"
20
21 U_NAMESPACE_BEGIN
22
23 static const UChar kSuperscriptDigits[] = {
24 0x2070,
25 0xB9,
26 0xB2,
27 0xB3,
28 0x2074,
29 0x2075,
30 0x2076,
31 0x2077,
32 0x2078,
33 0x2079};
34
35 static const UChar kSuperscriptPlusSign = 0x207A;
36 static const UChar kSuperscriptMinusSign = 0x207B;
37
copyAsSuperscript(const UnicodeString & s,int32_t beginIndex,int32_t endIndex,UnicodeString & result,UErrorCode & status)38 static UBool copyAsSuperscript(
39 const UnicodeString &s,
40 int32_t beginIndex,
41 int32_t endIndex,
42 UnicodeString &result,
43 UErrorCode &status) {
44 if (U_FAILURE(status)) {
45 return FALSE;
46 }
47 for (int32_t i = beginIndex; i < endIndex;) {
48 UChar32 c = s.char32At(i);
49 int32_t digit = u_charDigitValue(c);
50 if (digit < 0) {
51 status = U_INVALID_CHAR_FOUND;
52 return FALSE;
53 }
54 result.append(kSuperscriptDigits[digit]);
55 i += U16_LENGTH(c);
56 }
57 return TRUE;
58 }
59
createSuperscriptInstance(DecimalFormat * fmtToAdopt,UErrorCode & status)60 ScientificNumberFormatter *ScientificNumberFormatter::createSuperscriptInstance(
61 DecimalFormat *fmtToAdopt, UErrorCode &status) {
62 return createInstance(fmtToAdopt, new SuperscriptStyle(), status);
63 }
64
createSuperscriptInstance(const Locale & locale,UErrorCode & status)65 ScientificNumberFormatter *ScientificNumberFormatter::createSuperscriptInstance(
66 const Locale &locale, UErrorCode &status) {
67 return createInstance(
68 static_cast<DecimalFormat *>(
69 DecimalFormat::createScientificInstance(locale, status)),
70 new SuperscriptStyle(),
71 status);
72 }
73
createMarkupInstance(DecimalFormat * fmtToAdopt,const UnicodeString & beginMarkup,const UnicodeString & endMarkup,UErrorCode & status)74 ScientificNumberFormatter *ScientificNumberFormatter::createMarkupInstance(
75 DecimalFormat *fmtToAdopt,
76 const UnicodeString &beginMarkup,
77 const UnicodeString &endMarkup,
78 UErrorCode &status) {
79 return createInstance(
80 fmtToAdopt,
81 new MarkupStyle(beginMarkup, endMarkup),
82 status);
83 }
84
createMarkupInstance(const Locale & locale,const UnicodeString & beginMarkup,const UnicodeString & endMarkup,UErrorCode & status)85 ScientificNumberFormatter *ScientificNumberFormatter::createMarkupInstance(
86 const Locale &locale,
87 const UnicodeString &beginMarkup,
88 const UnicodeString &endMarkup,
89 UErrorCode &status) {
90 return createInstance(
91 static_cast<DecimalFormat *>(
92 DecimalFormat::createScientificInstance(locale, status)),
93 new MarkupStyle(beginMarkup, endMarkup),
94 status);
95 }
96
createInstance(DecimalFormat * fmtToAdopt,Style * styleToAdopt,UErrorCode & status)97 ScientificNumberFormatter *ScientificNumberFormatter::createInstance(
98 DecimalFormat *fmtToAdopt,
99 Style *styleToAdopt,
100 UErrorCode &status) {
101 LocalPointer<DecimalFormat> fmt(fmtToAdopt);
102 LocalPointer<Style> style(styleToAdopt);
103 if (U_FAILURE(status)) {
104 return NULL;
105 }
106 ScientificNumberFormatter *result =
107 new ScientificNumberFormatter(
108 fmt.getAlias(),
109 style.getAlias(),
110 status);
111 if (result == NULL) {
112 status = U_MEMORY_ALLOCATION_ERROR;
113 return NULL;
114 }
115 fmt.orphan();
116 style.orphan();
117 if (U_FAILURE(status)) {
118 delete result;
119 return NULL;
120 }
121 return result;
122 }
123
clone() const124 ScientificNumberFormatter::Style *ScientificNumberFormatter::SuperscriptStyle::clone() const {
125 return new ScientificNumberFormatter::SuperscriptStyle(*this);
126 }
127
format(const UnicodeString & original,FieldPositionIterator & fpi,const UnicodeString & preExponent,UnicodeString & appendTo,UErrorCode & status) const128 UnicodeString &ScientificNumberFormatter::SuperscriptStyle::format(
129 const UnicodeString &original,
130 FieldPositionIterator &fpi,
131 const UnicodeString &preExponent,
132 UnicodeString &appendTo,
133 UErrorCode &status) const {
134 if (U_FAILURE(status)) {
135 return appendTo;
136 }
137 FieldPosition fp;
138 int32_t copyFromOffset = 0;
139 while (fpi.next(fp)) {
140 switch (fp.getField()) {
141 case UNUM_EXPONENT_SYMBOL_FIELD:
142 appendTo.append(
143 original,
144 copyFromOffset,
145 fp.getBeginIndex() - copyFromOffset);
146 copyFromOffset = fp.getEndIndex();
147 appendTo.append(preExponent);
148 break;
149 case UNUM_EXPONENT_SIGN_FIELD:
150 {
151 using namespace icu::numparse::impl;
152 int32_t beginIndex = fp.getBeginIndex();
153 int32_t endIndex = fp.getEndIndex();
154 UChar32 aChar = original.char32At(beginIndex);
155 if (unisets::get(unisets::MINUS_SIGN)->contains(aChar)) {
156 appendTo.append(
157 original,
158 copyFromOffset,
159 beginIndex - copyFromOffset);
160 appendTo.append(kSuperscriptMinusSign);
161 } else if (unisets::get(unisets::PLUS_SIGN)->contains(aChar)) {
162 appendTo.append(
163 original,
164 copyFromOffset,
165 beginIndex - copyFromOffset);
166 appendTo.append(kSuperscriptPlusSign);
167 } else {
168 status = U_INVALID_CHAR_FOUND;
169 return appendTo;
170 }
171 copyFromOffset = endIndex;
172 }
173 break;
174 case UNUM_EXPONENT_FIELD:
175 appendTo.append(
176 original,
177 copyFromOffset,
178 fp.getBeginIndex() - copyFromOffset);
179 if (!copyAsSuperscript(
180 original,
181 fp.getBeginIndex(),
182 fp.getEndIndex(),
183 appendTo,
184 status)) {
185 return appendTo;
186 }
187 copyFromOffset = fp.getEndIndex();
188 break;
189 default:
190 break;
191 }
192 }
193 appendTo.append(
194 original, copyFromOffset, original.length() - copyFromOffset);
195 return appendTo;
196 }
197
clone() const198 ScientificNumberFormatter::Style *ScientificNumberFormatter::MarkupStyle::clone() const {
199 return new ScientificNumberFormatter::MarkupStyle(*this);
200 }
201
format(const UnicodeString & original,FieldPositionIterator & fpi,const UnicodeString & preExponent,UnicodeString & appendTo,UErrorCode & status) const202 UnicodeString &ScientificNumberFormatter::MarkupStyle::format(
203 const UnicodeString &original,
204 FieldPositionIterator &fpi,
205 const UnicodeString &preExponent,
206 UnicodeString &appendTo,
207 UErrorCode &status) const {
208 if (U_FAILURE(status)) {
209 return appendTo;
210 }
211 FieldPosition fp;
212 int32_t copyFromOffset = 0;
213 while (fpi.next(fp)) {
214 switch (fp.getField()) {
215 case UNUM_EXPONENT_SYMBOL_FIELD:
216 appendTo.append(
217 original,
218 copyFromOffset,
219 fp.getBeginIndex() - copyFromOffset);
220 copyFromOffset = fp.getEndIndex();
221 appendTo.append(preExponent);
222 appendTo.append(fBeginMarkup);
223 break;
224 case UNUM_EXPONENT_FIELD:
225 appendTo.append(
226 original,
227 copyFromOffset,
228 fp.getEndIndex() - copyFromOffset);
229 copyFromOffset = fp.getEndIndex();
230 appendTo.append(fEndMarkup);
231 break;
232 default:
233 break;
234 }
235 }
236 appendTo.append(
237 original, copyFromOffset, original.length() - copyFromOffset);
238 return appendTo;
239 }
240
ScientificNumberFormatter(DecimalFormat * fmtToAdopt,Style * styleToAdopt,UErrorCode & status)241 ScientificNumberFormatter::ScientificNumberFormatter(
242 DecimalFormat *fmtToAdopt, Style *styleToAdopt, UErrorCode &status)
243 : fPreExponent(),
244 fDecimalFormat(fmtToAdopt),
245 fStyle(styleToAdopt) {
246 if (U_FAILURE(status)) {
247 return;
248 }
249 if (fDecimalFormat == NULL || fStyle == NULL) {
250 status = U_ILLEGAL_ARGUMENT_ERROR;
251 return;
252 }
253 const DecimalFormatSymbols *sym = fDecimalFormat->getDecimalFormatSymbols();
254 if (sym == NULL) {
255 status = U_ILLEGAL_ARGUMENT_ERROR;
256 return;
257 }
258 getPreExponent(*sym, fPreExponent);
259 }
260
ScientificNumberFormatter(const ScientificNumberFormatter & other)261 ScientificNumberFormatter::ScientificNumberFormatter(
262 const ScientificNumberFormatter &other)
263 : UObject(other),
264 fPreExponent(other.fPreExponent),
265 fDecimalFormat(NULL),
266 fStyle(NULL) {
267 fDecimalFormat = static_cast<DecimalFormat *>(
268 other.fDecimalFormat->clone());
269 fStyle = other.fStyle->clone();
270 }
271
~ScientificNumberFormatter()272 ScientificNumberFormatter::~ScientificNumberFormatter() {
273 delete fDecimalFormat;
274 delete fStyle;
275 }
276
format(const Formattable & number,UnicodeString & appendTo,UErrorCode & status) const277 UnicodeString &ScientificNumberFormatter::format(
278 const Formattable &number,
279 UnicodeString &appendTo,
280 UErrorCode &status) const {
281 if (U_FAILURE(status)) {
282 return appendTo;
283 }
284 UnicodeString original;
285 FieldPositionIterator fpi;
286 fDecimalFormat->format(number, original, &fpi, status);
287 return fStyle->format(
288 original,
289 fpi,
290 fPreExponent,
291 appendTo,
292 status);
293 }
294
getPreExponent(const DecimalFormatSymbols & dfs,UnicodeString & preExponent)295 void ScientificNumberFormatter::getPreExponent(
296 const DecimalFormatSymbols &dfs, UnicodeString &preExponent) {
297 preExponent.append(dfs.getConstSymbol(
298 DecimalFormatSymbols::kExponentMultiplicationSymbol));
299 preExponent.append(dfs.getConstSymbol(DecimalFormatSymbols::kOneDigitSymbol));
300 preExponent.append(dfs.getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol));
301 }
302
303 U_NAMESPACE_END
304
305 #endif /* !UCONFIG_NO_FORMATTING */
306