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