1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 **********************************************************************
5 * Copyright (c) 2014, International Business Machines
6 * Corporation and others. All Rights Reserved.
7 **********************************************************************
9 #include "unicode/utypes.h"
11 #if !UCONFIG_NO_FORMATTING
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"
19 #include "unicode/decimfmt.h"
23 static const UChar kSuperscriptDigits
[] = {
35 static const UChar kSuperscriptPlusSign
= 0x207A;
36 static const UChar kSuperscriptMinusSign
= 0x207B;
38 static UBool
copyAsSuperscript(
39 const UnicodeString
&s
,
42 UnicodeString
&result
,
44 if (U_FAILURE(status
)) {
47 for (int32_t i
= beginIndex
; i
< endIndex
;) {
48 UChar32 c
= s
.char32At(i
);
49 int32_t digit
= u_charDigitValue(c
);
51 status
= U_INVALID_CHAR_FOUND
;
54 result
.append(kSuperscriptDigits
[digit
]);
60 ScientificNumberFormatter
*ScientificNumberFormatter::createSuperscriptInstance(
61 DecimalFormat
*fmtToAdopt
, UErrorCode
&status
) {
62 return createInstance(fmtToAdopt
, new SuperscriptStyle(), 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(),
74 ScientificNumberFormatter
*ScientificNumberFormatter::createMarkupInstance(
75 DecimalFormat
*fmtToAdopt
,
76 const UnicodeString
&beginMarkup
,
77 const UnicodeString
&endMarkup
,
79 return createInstance(
81 new MarkupStyle(beginMarkup
, endMarkup
),
85 ScientificNumberFormatter
*ScientificNumberFormatter::createMarkupInstance(
87 const UnicodeString
&beginMarkup
,
88 const UnicodeString
&endMarkup
,
90 return createInstance(
91 static_cast<DecimalFormat
*>(
92 DecimalFormat::createScientificInstance(locale
, status
)),
93 new MarkupStyle(beginMarkup
, endMarkup
),
97 ScientificNumberFormatter
*ScientificNumberFormatter::createInstance(
98 DecimalFormat
*fmtToAdopt
,
100 UErrorCode
&status
) {
101 LocalPointer
<DecimalFormat
> fmt(fmtToAdopt
);
102 LocalPointer
<Style
> style(styleToAdopt
);
103 if (U_FAILURE(status
)) {
106 ScientificNumberFormatter
*result
=
107 new ScientificNumberFormatter(
111 if (result
== NULL
) {
112 status
= U_MEMORY_ALLOCATION_ERROR
;
117 if (U_FAILURE(status
)) {
124 ScientificNumberFormatter::Style
*ScientificNumberFormatter::SuperscriptStyle::clone() const {
125 return new ScientificNumberFormatter::SuperscriptStyle(*this);
128 UnicodeString
&ScientificNumberFormatter::SuperscriptStyle::format(
129 const UnicodeString
&original
,
130 FieldPositionIterator
&fpi
,
131 const UnicodeString
&preExponent
,
132 const DecimalFormatStaticSets
&staticSets
,
133 UnicodeString
&appendTo
,
134 UErrorCode
&status
) const {
135 if (U_FAILURE(status
)) {
139 int32_t copyFromOffset
= 0;
140 while (fpi
.next(fp
)) {
141 switch (fp
.getField()) {
142 case UNUM_EXPONENT_SYMBOL_FIELD
:
146 fp
.getBeginIndex() - copyFromOffset
);
147 copyFromOffset
= fp
.getEndIndex();
148 appendTo
.append(preExponent
);
150 case UNUM_EXPONENT_SIGN_FIELD
:
152 int32_t beginIndex
= fp
.getBeginIndex();
153 int32_t endIndex
= fp
.getEndIndex();
154 UChar32 aChar
= original
.char32At(beginIndex
);
155 if (staticSets
.fMinusSigns
->contains(aChar
)) {
159 beginIndex
- copyFromOffset
);
160 appendTo
.append(kSuperscriptMinusSign
);
161 } else if (staticSets
.fPlusSigns
->contains(aChar
)) {
165 beginIndex
- copyFromOffset
);
166 appendTo
.append(kSuperscriptPlusSign
);
168 status
= U_INVALID_CHAR_FOUND
;
171 copyFromOffset
= endIndex
;
174 case UNUM_EXPONENT_FIELD
:
178 fp
.getBeginIndex() - copyFromOffset
);
179 if (!copyAsSuperscript(
187 copyFromOffset
= fp
.getEndIndex();
194 original
, copyFromOffset
, original
.length() - copyFromOffset
);
198 ScientificNumberFormatter::Style
*ScientificNumberFormatter::MarkupStyle::clone() const {
199 return new ScientificNumberFormatter::MarkupStyle(*this);
202 UnicodeString
&ScientificNumberFormatter::MarkupStyle::format(
203 const UnicodeString
&original
,
204 FieldPositionIterator
&fpi
,
205 const UnicodeString
&preExponent
,
206 const DecimalFormatStaticSets
& /*unusedDecimalFormatSets*/,
207 UnicodeString
&appendTo
,
208 UErrorCode
&status
) const {
209 if (U_FAILURE(status
)) {
213 int32_t copyFromOffset
= 0;
214 while (fpi
.next(fp
)) {
215 switch (fp
.getField()) {
216 case UNUM_EXPONENT_SYMBOL_FIELD
:
220 fp
.getBeginIndex() - copyFromOffset
);
221 copyFromOffset
= fp
.getEndIndex();
222 appendTo
.append(preExponent
);
223 appendTo
.append(fBeginMarkup
);
225 case UNUM_EXPONENT_FIELD
:
229 fp
.getEndIndex() - copyFromOffset
);
230 copyFromOffset
= fp
.getEndIndex();
231 appendTo
.append(fEndMarkup
);
238 original
, copyFromOffset
, original
.length() - copyFromOffset
);
242 ScientificNumberFormatter::ScientificNumberFormatter(
243 DecimalFormat
*fmtToAdopt
, Style
*styleToAdopt
, UErrorCode
&status
)
245 fDecimalFormat(fmtToAdopt
),
246 fStyle(styleToAdopt
),
248 if (U_FAILURE(status
)) {
251 if (fDecimalFormat
== NULL
|| fStyle
== NULL
) {
252 status
= U_ILLEGAL_ARGUMENT_ERROR
;
255 const DecimalFormatSymbols
*sym
= fDecimalFormat
->getDecimalFormatSymbols();
257 status
= U_ILLEGAL_ARGUMENT_ERROR
;
260 getPreExponent(*sym
, fPreExponent
);
261 fStaticSets
= DecimalFormatStaticSets::getStaticSets(status
);
264 ScientificNumberFormatter::ScientificNumberFormatter(
265 const ScientificNumberFormatter
&other
)
267 fPreExponent(other
.fPreExponent
),
268 fDecimalFormat(NULL
),
270 fStaticSets(other
.fStaticSets
) {
271 fDecimalFormat
= static_cast<DecimalFormat
*>(
272 other
.fDecimalFormat
->clone());
273 fStyle
= other
.fStyle
->clone();
276 ScientificNumberFormatter::~ScientificNumberFormatter() {
277 delete fDecimalFormat
;
281 UnicodeString
&ScientificNumberFormatter::format(
282 const Formattable
&number
,
283 UnicodeString
&appendTo
,
284 UErrorCode
&status
) const {
285 if (U_FAILURE(status
)) {
288 UnicodeString original
;
289 FieldPositionIterator fpi
;
290 fDecimalFormat
->format(number
, original
, &fpi
, status
);
291 return fStyle
->format(
300 void ScientificNumberFormatter::getPreExponent(
301 const DecimalFormatSymbols
&dfs
, UnicodeString
&preExponent
) {
302 preExponent
.append(dfs
.getConstSymbol(
303 DecimalFormatSymbols::kExponentMultiplicationSymbol
));
304 preExponent
.append(dfs
.getConstSymbol(DecimalFormatSymbols::kOneDigitSymbol
));
305 preExponent
.append(dfs
.getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol
));
310 #endif /* !UCONFIG_NO_FORMATTING */