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