blob: 6c2cb3aeed27433b79bf0fda128bb20fb497eed7 [file] [log] [blame]
// © 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 */