diff options
Diffstat (limited to 'intl/icu/source/i18n/scientificnumberformatter.cpp')
-rw-r--r-- | intl/icu/source/i18n/scientificnumberformatter.cpp | 305 |
1 files changed, 305 insertions, 0 deletions
diff --git a/intl/icu/source/i18n/scientificnumberformatter.cpp b/intl/icu/source/i18n/scientificnumberformatter.cpp new file mode 100644 index 0000000000..6c2cb3aeed --- /dev/null +++ b/intl/icu/source/i18n/scientificnumberformatter.cpp @@ -0,0 +1,305 @@ +// © 2016 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html +/* +********************************************************************** +* Copyright (c) 2014, International Business Machines +* Corporation and others. All Rights Reserved. +********************************************************************** +*/ +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +#include "unicode/scientificnumberformatter.h" +#include "unicode/dcfmtsym.h" +#include "unicode/fpositer.h" +#include "unicode/utf16.h" +#include "unicode/uniset.h" +#include "unicode/decimfmt.h" +#include "static_unicode_sets.h" + +U_NAMESPACE_BEGIN + +static const UChar kSuperscriptDigits[] = { + 0x2070, + 0xB9, + 0xB2, + 0xB3, + 0x2074, + 0x2075, + 0x2076, + 0x2077, + 0x2078, + 0x2079}; + +static const UChar kSuperscriptPlusSign = 0x207A; +static const UChar kSuperscriptMinusSign = 0x207B; + +static UBool copyAsSuperscript( + const UnicodeString &s, + int32_t beginIndex, + int32_t endIndex, + UnicodeString &result, + UErrorCode &status) { + if (U_FAILURE(status)) { + return FALSE; + } + for (int32_t i = beginIndex; i < endIndex;) { + UChar32 c = s.char32At(i); + int32_t digit = u_charDigitValue(c); + if (digit < 0) { + status = U_INVALID_CHAR_FOUND; + return FALSE; + } + result.append(kSuperscriptDigits[digit]); + i += U16_LENGTH(c); + } + return TRUE; +} + +ScientificNumberFormatter *ScientificNumberFormatter::createSuperscriptInstance( + DecimalFormat *fmtToAdopt, UErrorCode &status) { + return createInstance(fmtToAdopt, new SuperscriptStyle(), status); +} + +ScientificNumberFormatter *ScientificNumberFormatter::createSuperscriptInstance( + const Locale &locale, UErrorCode &status) { + return createInstance( + static_cast<DecimalFormat *>( + DecimalFormat::createScientificInstance(locale, status)), + new SuperscriptStyle(), + status); +} + +ScientificNumberFormatter *ScientificNumberFormatter::createMarkupInstance( + DecimalFormat *fmtToAdopt, + const UnicodeString &beginMarkup, + const UnicodeString &endMarkup, + UErrorCode &status) { + return createInstance( + fmtToAdopt, + new MarkupStyle(beginMarkup, endMarkup), + status); +} + +ScientificNumberFormatter *ScientificNumberFormatter::createMarkupInstance( + const Locale &locale, + const UnicodeString &beginMarkup, + const UnicodeString &endMarkup, + UErrorCode &status) { + return createInstance( + static_cast<DecimalFormat *>( + DecimalFormat::createScientificInstance(locale, status)), + new MarkupStyle(beginMarkup, endMarkup), + status); +} + +ScientificNumberFormatter *ScientificNumberFormatter::createInstance( + DecimalFormat *fmtToAdopt, + Style *styleToAdopt, + UErrorCode &status) { + LocalPointer<DecimalFormat> fmt(fmtToAdopt); + LocalPointer<Style> style(styleToAdopt); + if (U_FAILURE(status)) { + return NULL; + } + ScientificNumberFormatter *result = + new ScientificNumberFormatter( + fmt.getAlias(), + style.getAlias(), + status); + if (result == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + return NULL; + } + fmt.orphan(); + style.orphan(); + if (U_FAILURE(status)) { + delete result; + return NULL; + } + return result; +} + +ScientificNumberFormatter::SuperscriptStyle *ScientificNumberFormatter::SuperscriptStyle::clone() const { + return new ScientificNumberFormatter::SuperscriptStyle(*this); +} + +UnicodeString &ScientificNumberFormatter::SuperscriptStyle::format( + const UnicodeString &original, + FieldPositionIterator &fpi, + const UnicodeString &preExponent, + UnicodeString &appendTo, + UErrorCode &status) const { + if (U_FAILURE(status)) { + return appendTo; + } + FieldPosition fp; + int32_t copyFromOffset = 0; + while (fpi.next(fp)) { + switch (fp.getField()) { + case UNUM_EXPONENT_SYMBOL_FIELD: + appendTo.append( + original, + copyFromOffset, + fp.getBeginIndex() - copyFromOffset); + copyFromOffset = fp.getEndIndex(); + appendTo.append(preExponent); + break; + case UNUM_EXPONENT_SIGN_FIELD: + { + using namespace icu::numparse::impl; + int32_t beginIndex = fp.getBeginIndex(); + int32_t endIndex = fp.getEndIndex(); + UChar32 aChar = original.char32At(beginIndex); + if (unisets::get(unisets::MINUS_SIGN)->contains(aChar)) { + appendTo.append( + original, + copyFromOffset, + beginIndex - copyFromOffset); + appendTo.append(kSuperscriptMinusSign); + } else if (unisets::get(unisets::PLUS_SIGN)->contains(aChar)) { + appendTo.append( + original, + copyFromOffset, + beginIndex - copyFromOffset); + appendTo.append(kSuperscriptPlusSign); + } else { + status = U_INVALID_CHAR_FOUND; + return appendTo; + } + copyFromOffset = endIndex; + } + break; + case UNUM_EXPONENT_FIELD: + appendTo.append( + original, + copyFromOffset, + fp.getBeginIndex() - copyFromOffset); + if (!copyAsSuperscript( + original, + fp.getBeginIndex(), + fp.getEndIndex(), + appendTo, + status)) { + return appendTo; + } + copyFromOffset = fp.getEndIndex(); + break; + default: + break; + } + } + appendTo.append( + original, copyFromOffset, original.length() - copyFromOffset); + return appendTo; +} + +ScientificNumberFormatter::MarkupStyle *ScientificNumberFormatter::MarkupStyle::clone() const { + return new ScientificNumberFormatter::MarkupStyle(*this); +} + +UnicodeString &ScientificNumberFormatter::MarkupStyle::format( + const UnicodeString &original, + FieldPositionIterator &fpi, + const UnicodeString &preExponent, + UnicodeString &appendTo, + UErrorCode &status) const { + if (U_FAILURE(status)) { + return appendTo; + } + FieldPosition fp; + int32_t copyFromOffset = 0; + while (fpi.next(fp)) { + switch (fp.getField()) { + case UNUM_EXPONENT_SYMBOL_FIELD: + appendTo.append( + original, + copyFromOffset, + fp.getBeginIndex() - copyFromOffset); + copyFromOffset = fp.getEndIndex(); + appendTo.append(preExponent); + appendTo.append(fBeginMarkup); + break; + case UNUM_EXPONENT_FIELD: + appendTo.append( + original, + copyFromOffset, + fp.getEndIndex() - copyFromOffset); + copyFromOffset = fp.getEndIndex(); + appendTo.append(fEndMarkup); + break; + default: + break; + } + } + appendTo.append( + original, copyFromOffset, original.length() - copyFromOffset); + return appendTo; +} + +ScientificNumberFormatter::ScientificNumberFormatter( + DecimalFormat *fmtToAdopt, Style *styleToAdopt, UErrorCode &status) + : fPreExponent(), + fDecimalFormat(fmtToAdopt), + fStyle(styleToAdopt) { + if (U_FAILURE(status)) { + return; + } + if (fDecimalFormat == NULL || fStyle == NULL) { + status = U_ILLEGAL_ARGUMENT_ERROR; + return; + } + const DecimalFormatSymbols *sym = fDecimalFormat->getDecimalFormatSymbols(); + if (sym == NULL) { + status = U_ILLEGAL_ARGUMENT_ERROR; + return; + } + getPreExponent(*sym, fPreExponent); +} + +ScientificNumberFormatter::ScientificNumberFormatter( + const ScientificNumberFormatter &other) + : UObject(other), + fPreExponent(other.fPreExponent), + fDecimalFormat(NULL), + fStyle(NULL) { + fDecimalFormat = static_cast<DecimalFormat *>( + other.fDecimalFormat->clone()); + fStyle = other.fStyle->clone(); +} + +ScientificNumberFormatter::~ScientificNumberFormatter() { + delete fDecimalFormat; + delete fStyle; +} + +UnicodeString &ScientificNumberFormatter::format( + const Formattable &number, + UnicodeString &appendTo, + UErrorCode &status) const { + if (U_FAILURE(status)) { + return appendTo; + } + UnicodeString original; + FieldPositionIterator fpi; + fDecimalFormat->format(number, original, &fpi, status); + return fStyle->format( + original, + fpi, + fPreExponent, + appendTo, + status); +} + +void ScientificNumberFormatter::getPreExponent( + const DecimalFormatSymbols &dfs, UnicodeString &preExponent) { + preExponent.append(dfs.getConstSymbol( + DecimalFormatSymbols::kExponentMultiplicationSymbol)); + preExponent.append(dfs.getConstSymbol(DecimalFormatSymbols::kOneDigitSymbol)); + preExponent.append(dfs.getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol)); +} + +U_NAMESPACE_END + +#endif /* !UCONFIG_NO_FORMATTING */ |