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 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 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 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 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 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 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 272 ScientificNumberFormatter::~ScientificNumberFormatter() { 273 delete fDecimalFormat; 274 delete fStyle; 275 } 276 277 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 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