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