Home | History | Annotate | Download | only in i18n
      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