1 // Copyright (C) 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 "decfmtst.h" 19 #include "unicode/decimfmt.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 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 60 ScientificNumberFormatter *ScientificNumberFormatter::createSuperscriptInstance( 61 DecimalFormat *fmtToAdopt, UErrorCode &status) { 62 return createInstance(fmtToAdopt, new SuperscriptStyle(), status); 63 } 64 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 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 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 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 124 ScientificNumberFormatter::Style *ScientificNumberFormatter::SuperscriptStyle::clone() const { 125 return new ScientificNumberFormatter::SuperscriptStyle(*this); 126 } 127 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)) { 136 return appendTo; 137 } 138 FieldPosition fp; 139 int32_t copyFromOffset = 0; 140 while (fpi.next(fp)) { 141 switch (fp.getField()) { 142 case UNUM_EXPONENT_SYMBOL_FIELD: 143 appendTo.append( 144 original, 145 copyFromOffset, 146 fp.getBeginIndex() - copyFromOffset); 147 copyFromOffset = fp.getEndIndex(); 148 appendTo.append(preExponent); 149 break; 150 case UNUM_EXPONENT_SIGN_FIELD: 151 { 152 int32_t beginIndex = fp.getBeginIndex(); 153 int32_t endIndex = fp.getEndIndex(); 154 UChar32 aChar = original.char32At(beginIndex); 155 if (staticSets.fMinusSigns->contains(aChar)) { 156 appendTo.append( 157 original, 158 copyFromOffset, 159 beginIndex - copyFromOffset); 160 appendTo.append(kSuperscriptMinusSign); 161 } else if (staticSets.fPlusSigns->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 198 ScientificNumberFormatter::Style *ScientificNumberFormatter::MarkupStyle::clone() const { 199 return new ScientificNumberFormatter::MarkupStyle(*this); 200 } 201 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)) { 210 return appendTo; 211 } 212 FieldPosition fp; 213 int32_t copyFromOffset = 0; 214 while (fpi.next(fp)) { 215 switch (fp.getField()) { 216 case UNUM_EXPONENT_SYMBOL_FIELD: 217 appendTo.append( 218 original, 219 copyFromOffset, 220 fp.getBeginIndex() - copyFromOffset); 221 copyFromOffset = fp.getEndIndex(); 222 appendTo.append(preExponent); 223 appendTo.append(fBeginMarkup); 224 break; 225 case UNUM_EXPONENT_FIELD: 226 appendTo.append( 227 original, 228 copyFromOffset, 229 fp.getEndIndex() - copyFromOffset); 230 copyFromOffset = fp.getEndIndex(); 231 appendTo.append(fEndMarkup); 232 break; 233 default: 234 break; 235 } 236 } 237 appendTo.append( 238 original, copyFromOffset, original.length() - copyFromOffset); 239 return appendTo; 240 } 241 242 ScientificNumberFormatter::ScientificNumberFormatter( 243 DecimalFormat *fmtToAdopt, Style *styleToAdopt, UErrorCode &status) 244 : fPreExponent(), 245 fDecimalFormat(fmtToAdopt), 246 fStyle(styleToAdopt), 247 fStaticSets(NULL) { 248 if (U_FAILURE(status)) { 249 return; 250 } 251 if (fDecimalFormat == NULL || fStyle == NULL) { 252 status = U_ILLEGAL_ARGUMENT_ERROR; 253 return; 254 } 255 const DecimalFormatSymbols *sym = fDecimalFormat->getDecimalFormatSymbols(); 256 if (sym == NULL) { 257 status = U_ILLEGAL_ARGUMENT_ERROR; 258 return; 259 } 260 getPreExponent(*sym, fPreExponent); 261 fStaticSets = DecimalFormatStaticSets::getStaticSets(status); 262 } 263 264 ScientificNumberFormatter::ScientificNumberFormatter( 265 const ScientificNumberFormatter &other) 266 : UObject(other), 267 fPreExponent(other.fPreExponent), 268 fDecimalFormat(NULL), 269 fStyle(NULL), 270 fStaticSets(other.fStaticSets) { 271 fDecimalFormat = static_cast<DecimalFormat *>( 272 other.fDecimalFormat->clone()); 273 fStyle = other.fStyle->clone(); 274 } 275 276 ScientificNumberFormatter::~ScientificNumberFormatter() { 277 delete fDecimalFormat; 278 delete fStyle; 279 } 280 281 UnicodeString &ScientificNumberFormatter::format( 282 const Formattable &number, 283 UnicodeString &appendTo, 284 UErrorCode &status) const { 285 if (U_FAILURE(status)) { 286 return appendTo; 287 } 288 UnicodeString original; 289 FieldPositionIterator fpi; 290 fDecimalFormat->format(number, original, &fpi, status); 291 return fStyle->format( 292 original, 293 fpi, 294 fPreExponent, 295 *fStaticSets, 296 appendTo, 297 status); 298 } 299 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)); 306 } 307 308 U_NAMESPACE_END 309 310 #endif /* !UCONFIG_NO_FORMATTING */ 311