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"
18 #include "unicode/decimfmt.h"
19 #include "static_unicode_sets.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 UnicodeString
&appendTo
,
133 UErrorCode
&status
) const {
134 if (U_FAILURE(status
)) {
138 int32_t copyFromOffset
= 0;
139 while (fpi
.next(fp
)) {
140 switch (fp
.getField()) {
141 case UNUM_EXPONENT_SYMBOL_FIELD
:
145 fp
.getBeginIndex() - copyFromOffset
);
146 copyFromOffset
= fp
.getEndIndex();
147 appendTo
.append(preExponent
);
149 case UNUM_EXPONENT_SIGN_FIELD
:
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
)) {
159 beginIndex
- copyFromOffset
);
160 appendTo
.append(kSuperscriptMinusSign
);
161 } else if (unisets::get(unisets::PLUS_SIGN
)->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 UnicodeString
&appendTo
,
207 UErrorCode
&status
) const {
208 if (U_FAILURE(status
)) {
212 int32_t copyFromOffset
= 0;
213 while (fpi
.next(fp
)) {
214 switch (fp
.getField()) {
215 case UNUM_EXPONENT_SYMBOL_FIELD
:
219 fp
.getBeginIndex() - copyFromOffset
);
220 copyFromOffset
= fp
.getEndIndex();
221 appendTo
.append(preExponent
);
222 appendTo
.append(fBeginMarkup
);
224 case UNUM_EXPONENT_FIELD
:
228 fp
.getEndIndex() - copyFromOffset
);
229 copyFromOffset
= fp
.getEndIndex();
230 appendTo
.append(fEndMarkup
);
237 original
, copyFromOffset
, original
.length() - copyFromOffset
);
241 ScientificNumberFormatter::ScientificNumberFormatter(
242 DecimalFormat
*fmtToAdopt
, Style
*styleToAdopt
, UErrorCode
&status
)
244 fDecimalFormat(fmtToAdopt
),
245 fStyle(styleToAdopt
) {
246 if (U_FAILURE(status
)) {
249 if (fDecimalFormat
== NULL
|| fStyle
== NULL
) {
250 status
= U_ILLEGAL_ARGUMENT_ERROR
;
253 const DecimalFormatSymbols
*sym
= fDecimalFormat
->getDecimalFormatSymbols();
255 status
= U_ILLEGAL_ARGUMENT_ERROR
;
258 getPreExponent(*sym
, fPreExponent
);
261 ScientificNumberFormatter::ScientificNumberFormatter(
262 const ScientificNumberFormatter
&other
)
264 fPreExponent(other
.fPreExponent
),
265 fDecimalFormat(NULL
),
267 fDecimalFormat
= static_cast<DecimalFormat
*>(
268 other
.fDecimalFormat
->clone());
269 fStyle
= other
.fStyle
->clone();
272 ScientificNumberFormatter::~ScientificNumberFormatter() {
273 delete fDecimalFormat
;
277 UnicodeString
&ScientificNumberFormatter::format(
278 const Formattable
&number
,
279 UnicodeString
&appendTo
,
280 UErrorCode
&status
) const {
281 if (U_FAILURE(status
)) {
284 UnicodeString original
;
285 FieldPositionIterator fpi
;
286 fDecimalFormat
->format(number
, original
, &fpi
, status
);
287 return fStyle
->format(
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
));
305 #endif /* !UCONFIG_NO_FORMATTING */