ICU-13634 Implementing localized pattern converter and other pieces.
X-SVN-Rev: 41104
This commit is contained in:
parent
73fddf50d0
commit
f5d2257d34
@ -16,7 +16,7 @@ using namespace icu::number;
|
||||
using namespace icu::number::impl;
|
||||
|
||||
template<typename Derived>
|
||||
Derived NumberFormatterSettings<Derived>::notation(const Notation ¬ation) const {
|
||||
Derived NumberFormatterSettings<Derived>::notation(const Notation& notation) const {
|
||||
Derived copy(*this);
|
||||
// NOTE: Slicing is OK.
|
||||
copy.fMacros.notation = notation;
|
||||
@ -24,7 +24,7 @@ Derived NumberFormatterSettings<Derived>::notation(const Notation ¬ation) con
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
Derived NumberFormatterSettings<Derived>::unit(const icu::MeasureUnit &unit) const {
|
||||
Derived NumberFormatterSettings<Derived>::unit(const icu::MeasureUnit& unit) const {
|
||||
Derived copy(*this);
|
||||
// NOTE: Slicing occurs here. However, CurrencyUnit can be restored from MeasureUnit.
|
||||
// TimeUnit may be affected, but TimeUnit is not as relevant to number formatting.
|
||||
@ -33,13 +33,13 @@ Derived NumberFormatterSettings<Derived>::unit(const icu::MeasureUnit &unit) con
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
Derived NumberFormatterSettings<Derived>::adoptUnit(icu::MeasureUnit *unit) const {
|
||||
Derived NumberFormatterSettings<Derived>::adoptUnit(icu::MeasureUnit* unit) const {
|
||||
Derived copy(*this);
|
||||
// Just copy the unit into the MacroProps by value, and delete it since we have ownership.
|
||||
// NOTE: Slicing occurs here. However, CurrencyUnit can be restored from MeasureUnit.
|
||||
// TimeUnit may be affected, but TimeUnit is not as relevant to number formatting.
|
||||
if (unit != nullptr) {
|
||||
// TODO: On nullptr, reset to default value?
|
||||
// TODO: On nullptr, reset to default value?
|
||||
copy.fMacros.unit = *unit;
|
||||
delete unit;
|
||||
}
|
||||
@ -47,7 +47,7 @@ Derived NumberFormatterSettings<Derived>::adoptUnit(icu::MeasureUnit *unit) cons
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
Derived NumberFormatterSettings<Derived>::perUnit(const icu::MeasureUnit &perUnit) const {
|
||||
Derived NumberFormatterSettings<Derived>::perUnit(const icu::MeasureUnit& perUnit) const {
|
||||
Derived copy(*this);
|
||||
// See comments above about slicing.
|
||||
copy.fMacros.perUnit = perUnit;
|
||||
@ -55,11 +55,11 @@ Derived NumberFormatterSettings<Derived>::perUnit(const icu::MeasureUnit &perUni
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
Derived NumberFormatterSettings<Derived>::adoptPerUnit(icu::MeasureUnit *perUnit) const {
|
||||
Derived NumberFormatterSettings<Derived>::adoptPerUnit(icu::MeasureUnit* perUnit) const {
|
||||
Derived copy(*this);
|
||||
// See comments above about slicing and ownership.
|
||||
if (perUnit != nullptr) {
|
||||
// TODO: On nullptr, reset to default value?
|
||||
// TODO: On nullptr, reset to default value?
|
||||
copy.fMacros.perUnit = *perUnit;
|
||||
delete perUnit;
|
||||
}
|
||||
@ -67,7 +67,7 @@ Derived NumberFormatterSettings<Derived>::adoptPerUnit(icu::MeasureUnit *perUnit
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
Derived NumberFormatterSettings<Derived>::rounding(const Rounder &rounder) const {
|
||||
Derived NumberFormatterSettings<Derived>::rounding(const Rounder& rounder) const {
|
||||
Derived copy(*this);
|
||||
// NOTE: Slicing is OK.
|
||||
copy.fMacros.rounder = rounder;
|
||||
@ -75,7 +75,7 @@ Derived NumberFormatterSettings<Derived>::rounding(const Rounder &rounder) const
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
Derived NumberFormatterSettings<Derived>::grouping(const UGroupingStrategy &strategy) const {
|
||||
Derived NumberFormatterSettings<Derived>::grouping(const UGroupingStrategy& strategy) const {
|
||||
Derived copy(*this);
|
||||
// NOTE: This is slightly different than how the setting is stored in Java
|
||||
// because we want to put it on the stack.
|
||||
@ -84,49 +84,49 @@ Derived NumberFormatterSettings<Derived>::grouping(const UGroupingStrategy &stra
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
Derived NumberFormatterSettings<Derived>::integerWidth(const IntegerWidth &style) const {
|
||||
Derived NumberFormatterSettings<Derived>::integerWidth(const IntegerWidth& style) const {
|
||||
Derived copy(*this);
|
||||
copy.fMacros.integerWidth = style;
|
||||
return copy;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
Derived NumberFormatterSettings<Derived>::symbols(const DecimalFormatSymbols &symbols) const {
|
||||
Derived NumberFormatterSettings<Derived>::symbols(const DecimalFormatSymbols& symbols) const {
|
||||
Derived copy(*this);
|
||||
copy.fMacros.symbols.setTo(symbols);
|
||||
return copy;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
Derived NumberFormatterSettings<Derived>::adoptSymbols(NumberingSystem *ns) const {
|
||||
Derived NumberFormatterSettings<Derived>::adoptSymbols(NumberingSystem* ns) const {
|
||||
Derived copy(*this);
|
||||
copy.fMacros.symbols.setTo(ns);
|
||||
return copy;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
Derived NumberFormatterSettings<Derived>::unitWidth(const UNumberUnitWidth &width) const {
|
||||
Derived NumberFormatterSettings<Derived>::unitWidth(const UNumberUnitWidth& width) const {
|
||||
Derived copy(*this);
|
||||
copy.fMacros.unitWidth = width;
|
||||
return copy;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
Derived NumberFormatterSettings<Derived>::sign(const UNumberSignDisplay &style) const {
|
||||
Derived NumberFormatterSettings<Derived>::sign(const UNumberSignDisplay& style) const {
|
||||
Derived copy(*this);
|
||||
copy.fMacros.sign = style;
|
||||
return copy;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
Derived NumberFormatterSettings<Derived>::decimal(const UNumberDecimalSeparatorDisplay &style) const {
|
||||
Derived NumberFormatterSettings<Derived>::decimal(const UNumberDecimalSeparatorDisplay& style) const {
|
||||
Derived copy(*this);
|
||||
copy.fMacros.decimal = style;
|
||||
return copy;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
Derived NumberFormatterSettings<Derived>::padding(const Padder &padder) const {
|
||||
Derived NumberFormatterSettings<Derived>::padding(const Padder& padder) const {
|
||||
Derived copy(*this);
|
||||
copy.fMacros.padder = padder;
|
||||
return copy;
|
||||
@ -159,38 +159,38 @@ UnlocalizedNumberFormatter NumberFormatter::with() {
|
||||
return result;
|
||||
}
|
||||
|
||||
LocalizedNumberFormatter NumberFormatter::withLocale(const Locale &locale) {
|
||||
LocalizedNumberFormatter NumberFormatter::withLocale(const Locale& locale) {
|
||||
return with().locale(locale);
|
||||
}
|
||||
|
||||
// Make the child class constructor that takes the parent class call the parent class's copy constructor
|
||||
UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(
|
||||
const NumberFormatterSettings <UnlocalizedNumberFormatter> &other)
|
||||
const NumberFormatterSettings<UnlocalizedNumberFormatter>& other)
|
||||
: NumberFormatterSettings<UnlocalizedNumberFormatter>(other) {
|
||||
}
|
||||
|
||||
// Make the child class constructor that takes the parent class call the parent class's copy constructor
|
||||
// For LocalizedNumberFormatter, also copy over the extra fields
|
||||
LocalizedNumberFormatter::LocalizedNumberFormatter(
|
||||
const NumberFormatterSettings <LocalizedNumberFormatter> &other)
|
||||
const NumberFormatterSettings<LocalizedNumberFormatter>& other)
|
||||
: NumberFormatterSettings<LocalizedNumberFormatter>(other) {
|
||||
// No additional copies required
|
||||
}
|
||||
|
||||
LocalizedNumberFormatter::LocalizedNumberFormatter(const MacroProps ¯os, const Locale &locale) {
|
||||
LocalizedNumberFormatter::LocalizedNumberFormatter(const MacroProps& macros, const Locale& locale) {
|
||||
fMacros = macros;
|
||||
fMacros.locale = locale;
|
||||
}
|
||||
|
||||
LocalizedNumberFormatter UnlocalizedNumberFormatter::locale(const Locale &locale) const {
|
||||
LocalizedNumberFormatter UnlocalizedNumberFormatter::locale(const Locale& locale) const {
|
||||
return LocalizedNumberFormatter(fMacros, locale);
|
||||
}
|
||||
|
||||
SymbolsWrapper::SymbolsWrapper(const SymbolsWrapper &other) {
|
||||
SymbolsWrapper::SymbolsWrapper(const SymbolsWrapper& other) {
|
||||
doCopyFrom(other);
|
||||
}
|
||||
|
||||
SymbolsWrapper &SymbolsWrapper::operator=(const SymbolsWrapper &other) {
|
||||
SymbolsWrapper& SymbolsWrapper::operator=(const SymbolsWrapper& other) {
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
@ -203,19 +203,19 @@ SymbolsWrapper::~SymbolsWrapper() {
|
||||
doCleanup();
|
||||
}
|
||||
|
||||
void SymbolsWrapper::setTo(const DecimalFormatSymbols &dfs) {
|
||||
void SymbolsWrapper::setTo(const DecimalFormatSymbols& dfs) {
|
||||
doCleanup();
|
||||
fType = SYMPTR_DFS;
|
||||
fPtr.dfs = new DecimalFormatSymbols(dfs);
|
||||
}
|
||||
|
||||
void SymbolsWrapper::setTo(const NumberingSystem *ns) {
|
||||
void SymbolsWrapper::setTo(const NumberingSystem* ns) {
|
||||
doCleanup();
|
||||
fType = SYMPTR_NS;
|
||||
fPtr.ns = ns;
|
||||
}
|
||||
|
||||
void SymbolsWrapper::doCopyFrom(const SymbolsWrapper &other) {
|
||||
void SymbolsWrapper::doCopyFrom(const SymbolsWrapper& other) {
|
||||
fType = other.fType;
|
||||
switch (fType) {
|
||||
case SYMPTR_NONE:
|
||||
@ -276,7 +276,7 @@ LocalizedNumberFormatter::~LocalizedNumberFormatter() {
|
||||
delete fCompiled;
|
||||
}
|
||||
|
||||
FormattedNumber LocalizedNumberFormatter::formatInt(int64_t value, UErrorCode &status) const {
|
||||
FormattedNumber LocalizedNumberFormatter::formatInt(int64_t value, UErrorCode& status) const {
|
||||
if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); }
|
||||
auto results = new NumberFormatterResults();
|
||||
if (results == nullptr) {
|
||||
@ -287,7 +287,7 @@ FormattedNumber LocalizedNumberFormatter::formatInt(int64_t value, UErrorCode &s
|
||||
return formatImpl(results, status);
|
||||
}
|
||||
|
||||
FormattedNumber LocalizedNumberFormatter::formatDouble(double value, UErrorCode &status) const {
|
||||
FormattedNumber LocalizedNumberFormatter::formatDouble(double value, UErrorCode& status) const {
|
||||
if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); }
|
||||
auto results = new NumberFormatterResults();
|
||||
if (results == nullptr) {
|
||||
@ -298,7 +298,7 @@ FormattedNumber LocalizedNumberFormatter::formatDouble(double value, UErrorCode
|
||||
return formatImpl(results, status);
|
||||
}
|
||||
|
||||
FormattedNumber LocalizedNumberFormatter::formatDecimal(StringPiece value, UErrorCode &status) const {
|
||||
FormattedNumber LocalizedNumberFormatter::formatDecimal(StringPiece value, UErrorCode& status) const {
|
||||
if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); }
|
||||
auto results = new NumberFormatterResults();
|
||||
if (results == nullptr) {
|
||||
@ -309,7 +309,8 @@ FormattedNumber LocalizedNumberFormatter::formatDecimal(StringPiece value, UErro
|
||||
return formatImpl(results, status);
|
||||
}
|
||||
|
||||
FormattedNumber LocalizedNumberFormatter::formatDecimalQuantity(const DecimalQuantity& dq, UErrorCode &status) const {
|
||||
FormattedNumber
|
||||
LocalizedNumberFormatter::formatDecimalQuantity(const DecimalQuantity& dq, UErrorCode& status) const {
|
||||
if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); }
|
||||
auto results = new NumberFormatterResults();
|
||||
if (results == nullptr) {
|
||||
@ -321,15 +322,16 @@ FormattedNumber LocalizedNumberFormatter::formatDecimalQuantity(const DecimalQua
|
||||
}
|
||||
|
||||
FormattedNumber
|
||||
LocalizedNumberFormatter::formatImpl(impl::NumberFormatterResults *results, UErrorCode &status) const {
|
||||
LocalizedNumberFormatter::formatImpl(impl::NumberFormatterResults* results, UErrorCode& status) const {
|
||||
// fUnsafeCallCount contains memory to be interpreted as an atomic int, most commonly
|
||||
// std::atomic<int32_t>. Since the type of atomic int is platform-dependent, we cast the
|
||||
// bytes in fUnsafeCallCount to u_atomic_int32_t, a typedef for the platform-dependent
|
||||
// atomic int type defined in umutex.h.
|
||||
static_assert(sizeof(u_atomic_int32_t) <= sizeof(fUnsafeCallCount),
|
||||
"Atomic integer size on this platform exceeds the size allocated by fUnsafeCallCount");
|
||||
static_assert(
|
||||
sizeof(u_atomic_int32_t) <= sizeof(fUnsafeCallCount),
|
||||
"Atomic integer size on this platform exceeds the size allocated by fUnsafeCallCount");
|
||||
u_atomic_int32_t* callCount = reinterpret_cast<u_atomic_int32_t*>(
|
||||
const_cast<LocalizedNumberFormatter*>(this)->fUnsafeCallCount);
|
||||
const_cast<LocalizedNumberFormatter*>(this)->fUnsafeCallCount);
|
||||
|
||||
// A positive value in the atomic int indicates that the data structure is not yet ready;
|
||||
// a negative value indicates that it is ready. If, after the increment, the atomic int
|
||||
@ -343,10 +345,9 @@ LocalizedNumberFormatter::formatImpl(impl::NumberFormatterResults *results, UErr
|
||||
|
||||
if (currentCount == fMacros.threshold && fMacros.threshold > 0) {
|
||||
// Build the data structure and then use it (slow to fast path).
|
||||
const NumberFormatterImpl* compiled =
|
||||
NumberFormatterImpl::fromMacros(fMacros, status);
|
||||
const NumberFormatterImpl* compiled = NumberFormatterImpl::fromMacros(fMacros, status);
|
||||
U_ASSERT(fCompiled == nullptr);
|
||||
const_cast<LocalizedNumberFormatter *>(this)->fCompiled = compiled;
|
||||
const_cast<LocalizedNumberFormatter*>(this)->fCompiled = compiled;
|
||||
umtx_storeRelease(*callCount, INT32_MIN);
|
||||
compiled->apply(results->quantity, results->string, status);
|
||||
} else if (currentCount < 0) {
|
||||
@ -375,7 +376,7 @@ UnicodeString FormattedNumber::toString() const {
|
||||
return fResults->string.toUnicodeString();
|
||||
}
|
||||
|
||||
Appendable &FormattedNumber::appendTo(Appendable &appendable) {
|
||||
Appendable& FormattedNumber::appendTo(Appendable& appendable) {
|
||||
if (fResults == nullptr) {
|
||||
// TODO: http://bugs.icu-project.org/trac/ticket/13437
|
||||
return appendable;
|
||||
@ -384,7 +385,7 @@ Appendable &FormattedNumber::appendTo(Appendable &appendable) {
|
||||
return appendable;
|
||||
}
|
||||
|
||||
void FormattedNumber::populateFieldPosition(FieldPosition &fieldPosition, UErrorCode &status) {
|
||||
void FormattedNumber::populateFieldPosition(FieldPosition& fieldPosition, UErrorCode& status) {
|
||||
if (U_FAILURE(status)) { return; }
|
||||
if (fResults == nullptr) {
|
||||
status = fErrorCode;
|
||||
@ -393,8 +394,7 @@ void FormattedNumber::populateFieldPosition(FieldPosition &fieldPosition, UError
|
||||
fResults->string.populateFieldPosition(fieldPosition, 0, status);
|
||||
}
|
||||
|
||||
void
|
||||
FormattedNumber::populateFieldPositionIterator(FieldPositionIterator &iterator, UErrorCode &status) {
|
||||
void FormattedNumber::populateFieldPositionIterator(FieldPositionIterator& iterator, UErrorCode& status) {
|
||||
if (U_FAILURE(status)) { return; }
|
||||
if (fResults == nullptr) {
|
||||
status = fErrorCode;
|
||||
@ -403,6 +403,33 @@ FormattedNumber::populateFieldPositionIterator(FieldPositionIterator &iterator,
|
||||
fResults->string.populateFieldPositionIterator(iterator, status);
|
||||
}
|
||||
|
||||
void FormattedNumber::getDecimalQuantity(DecimalQuantity& output, UErrorCode& status) const {
|
||||
if (U_FAILURE(status)) { return; }
|
||||
if (fResults == nullptr) {
|
||||
status = fErrorCode;
|
||||
return;
|
||||
}
|
||||
output = fResults->quantity;
|
||||
}
|
||||
|
||||
const UnicodeString FormattedNumber::getPrefix(UErrorCode& status) const {
|
||||
if (fResults == nullptr) {
|
||||
status = fErrorCode;
|
||||
return {};
|
||||
}
|
||||
// FIXME
|
||||
return {};
|
||||
}
|
||||
|
||||
const UnicodeString FormattedNumber::getSuffix(UErrorCode& status) const {
|
||||
if (fResults == nullptr) {
|
||||
status = fErrorCode;
|
||||
return {};
|
||||
}
|
||||
// FIXME
|
||||
return {};
|
||||
}
|
||||
|
||||
FormattedNumber::~FormattedNumber() {
|
||||
delete fResults;
|
||||
}
|
||||
|
@ -16,7 +16,14 @@ using namespace icu::number;
|
||||
using namespace icu::number::impl;
|
||||
|
||||
|
||||
|
||||
UnlocalizedNumberFormatter NumberPropertyMapper::create(const DecimalFormatProperties& properties,
|
||||
const DecimalFormatSymbols& symbols,
|
||||
DecimalFormatProperties& exportedProperties,
|
||||
UErrorCode& status) {
|
||||
// TODO
|
||||
status = U_UNSUPPORTED_ERROR;
|
||||
return NumberFormatter::with();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -5,6 +5,11 @@
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT
|
||||
|
||||
// Allow implicit conversion from char16_t* to UnicodeString for this file:
|
||||
// Helpful in toString methods and elsewhere.
|
||||
#define UNISTR_FROM_STRING_EXPLICIT
|
||||
#define UNISTR_FROM_CHAR_EXPLICIT
|
||||
|
||||
#include "uassert.h"
|
||||
#include "number_patternstring.h"
|
||||
#include "unicode/utf16.h"
|
||||
@ -633,7 +638,7 @@ UnicodeString PatternStringUtils::propertiesToPatternString(const DecimalFormatP
|
||||
int groupingSize = uprv_min(properties.secondaryGroupingSize, dosMax);
|
||||
int firstGroupingSize = uprv_min(properties.groupingSize, dosMax);
|
||||
int paddingWidth = uprv_min(properties.formatWidth, dosMax);
|
||||
NullableValue <PadPosition> paddingLocation = properties.padPosition;
|
||||
NullableValue<PadPosition> paddingLocation = properties.padPosition;
|
||||
UnicodeString paddingString = properties.padString;
|
||||
int minInt = uprv_max(uprv_min(properties.minimumIntegerDigits, dosMax), 0);
|
||||
int maxInt = uprv_min(properties.maximumIntegerDigits, dosMax);
|
||||
@ -841,6 +846,144 @@ int PatternStringUtils::escapePaddingString(UnicodeString input, UnicodeString&
|
||||
return output.length() - startLength;
|
||||
}
|
||||
|
||||
UnicodeString
|
||||
PatternStringUtils::convertLocalized(UnicodeString input, DecimalFormatSymbols symbols, bool toLocalized,
|
||||
UErrorCode& status) {
|
||||
// Construct a table of strings to be converted between localized and standard.
|
||||
static constexpr int32_t LEN = 21;
|
||||
UnicodeString table[LEN][2];
|
||||
int standIdx = toLocalized ? 0 : 1;
|
||||
int localIdx = toLocalized ? 1 : 0;
|
||||
table[0][standIdx] = u"%";
|
||||
table[0][localIdx] = symbols.getConstSymbol(DecimalFormatSymbols::kPercentSymbol);
|
||||
table[1][standIdx] = u"‰";
|
||||
table[1][localIdx] = symbols.getConstSymbol(DecimalFormatSymbols::kPerMillSymbol);
|
||||
table[2][standIdx] = u".";
|
||||
table[2][localIdx] = symbols.getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
|
||||
table[3][standIdx] = u",";
|
||||
table[3][localIdx] = symbols.getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol);
|
||||
table[4][standIdx] = u"-";
|
||||
table[4][localIdx] = symbols.getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
|
||||
table[5][standIdx] = u"+";
|
||||
table[5][localIdx] = symbols.getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
|
||||
table[6][standIdx] = u";";
|
||||
table[6][localIdx] = symbols.getConstSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol);
|
||||
table[7][standIdx] = u"@";
|
||||
table[7][localIdx] = symbols.getConstSymbol(DecimalFormatSymbols::kSignificantDigitSymbol);
|
||||
table[8][standIdx] = u"E";
|
||||
table[8][localIdx] = symbols.getConstSymbol(DecimalFormatSymbols::kExponentialSymbol);
|
||||
table[9][standIdx] = u"*";
|
||||
table[9][localIdx] = symbols.getConstSymbol(DecimalFormatSymbols::kPadEscapeSymbol);
|
||||
table[10][standIdx] = u"#";
|
||||
table[10][localIdx] = symbols.getConstSymbol(DecimalFormatSymbols::kDigitSymbol);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
table[11 + i][standIdx] = u'0' + i;
|
||||
table[11 + i][localIdx] = symbols.getConstDigitSymbol(i);
|
||||
}
|
||||
|
||||
// Special case: quotes are NOT allowed to be in any localIdx strings.
|
||||
// Substitute them with '’' instead.
|
||||
for (int32_t i = 0; i < LEN; i++) {
|
||||
table[i][localIdx].findAndReplace(u'\'', u'’');
|
||||
}
|
||||
|
||||
// Iterate through the string and convert.
|
||||
// State table:
|
||||
// 0 => base state
|
||||
// 1 => first char inside a quoted sequence in input and output string
|
||||
// 2 => inside a quoted sequence in input and output string
|
||||
// 3 => first char after a close quote in input string;
|
||||
// close quote still needs to be written to output string
|
||||
// 4 => base state in input string; inside quoted sequence in output string
|
||||
// 5 => first char inside a quoted sequence in input string;
|
||||
// inside quoted sequence in output string
|
||||
UnicodeString result;
|
||||
int state = 0;
|
||||
for (int offset = 0; offset < input.length(); offset++) {
|
||||
UChar ch = input.charAt(offset);
|
||||
|
||||
// Handle a quote character (state shift)
|
||||
if (ch == u'\'') {
|
||||
if (state == 0) {
|
||||
result.append(u'\'');
|
||||
state = 1;
|
||||
continue;
|
||||
} else if (state == 1) {
|
||||
result.append(u'\'');
|
||||
state = 0;
|
||||
continue;
|
||||
} else if (state == 2) {
|
||||
state = 3;
|
||||
continue;
|
||||
} else if (state == 3) {
|
||||
result.append(u'\'');
|
||||
result.append(u'\'');
|
||||
state = 1;
|
||||
continue;
|
||||
} else if (state == 4) {
|
||||
state = 5;
|
||||
continue;
|
||||
} else {
|
||||
U_ASSERT(state == 5);
|
||||
result.append(u'\'');
|
||||
result.append(u'\'');
|
||||
state = 4;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (state == 0 || state == 3 || state == 4) {
|
||||
for (auto& pair : table) {
|
||||
// Perform a greedy match on this symbol string
|
||||
UnicodeString temp = input.tempSubString(offset, pair[0].length());
|
||||
if (temp == pair[0]) {
|
||||
// Skip ahead past this region for the next iteration
|
||||
offset += pair[0].length() - 1;
|
||||
if (state == 3 || state == 4) {
|
||||
result.append(u'\'');
|
||||
state = 0;
|
||||
}
|
||||
result.append(pair[1]);
|
||||
goto continue_outer;
|
||||
}
|
||||
}
|
||||
// No replacement found. Check if a special quote is necessary
|
||||
for (auto& pair : table) {
|
||||
UnicodeString temp = input.tempSubString(offset, pair[1].length());
|
||||
if (temp == pair[1]) {
|
||||
if (state == 0) {
|
||||
result.append(u'\'');
|
||||
state = 4;
|
||||
}
|
||||
result.append(ch);
|
||||
goto continue_outer;
|
||||
}
|
||||
}
|
||||
// Still nothing. Copy the char verbatim. (Add a close quote if necessary)
|
||||
if (state == 3 || state == 4) {
|
||||
result.append(u'\'');
|
||||
state = 0;
|
||||
}
|
||||
result.append(ch);
|
||||
} else {
|
||||
U_ASSERT(state == 1 || state == 2 || state == 5);
|
||||
result.append(ch);
|
||||
state = 2;
|
||||
}
|
||||
continue_outer:;
|
||||
}
|
||||
// Resolve final quotes
|
||||
if (state == 3 || state == 4) {
|
||||
result.append(u'\'');
|
||||
state = 0;
|
||||
}
|
||||
if (state != 0) {
|
||||
// Malformed localized pattern: unterminated quote
|
||||
status = U_PATTERN_SYNTAX_ERROR;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void PatternStringUtils::patternInfoToStringBuilder(const AffixPatternProvider& patternInfo, bool isPrefix,
|
||||
int8_t signum, UNumberSignDisplay signDisplay,
|
||||
StandardPlural::Form plural,
|
||||
|
@ -74,6 +74,14 @@ NumberParserImpl::createSimpleParser(const Locale& locale, const UnicodeString&
|
||||
return parser;
|
||||
}
|
||||
|
||||
NumberParserImpl* NumberParserImpl::createParserFromProperties(
|
||||
const number::impl::DecimalFormatProperties& properties, DecimalFormatSymbols symbols,
|
||||
bool parseCurrency, bool optimize, UErrorCode& status) {
|
||||
// TODO
|
||||
status = U_UNSUPPORTED_ERROR;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NumberParserImpl::NumberParserImpl(parse_flags_t parseFlags, bool computeLeads)
|
||||
: fParseFlags(parseFlags), fComputeLeads(computeLeads) {
|
||||
}
|
||||
|
@ -2147,11 +2147,10 @@ class U_I18N_API FormattedNumber : public UMemory {
|
||||
#ifndef U_HIDE_INTERNAL_API
|
||||
|
||||
/**
|
||||
* Get an IFixedDecimal for plural rule selection.
|
||||
* Internal, not intended for public use.
|
||||
* Gets the raw DecimalQuantity for plural rule selection.
|
||||
* @internal
|
||||
*/
|
||||
const IFixedDecimal& getFixedDecimal(UErrorCode& status) const;
|
||||
void getDecimalQuantity(impl::DecimalQuantity& output, UErrorCode& status) const;
|
||||
|
||||
/** @internal */
|
||||
const UnicodeString getPrefix(UErrorCode& status) const;
|
||||
|
@ -166,6 +166,7 @@ class PatternModifierTest : public IntlTest {
|
||||
|
||||
class PatternStringTest : public IntlTest {
|
||||
public:
|
||||
void testLocalized();
|
||||
void testToPatternSimple();
|
||||
void testExceptionOnInvalid();
|
||||
void testBug13117();
|
||||
|
@ -8,19 +8,42 @@
|
||||
#include "numbertest.h"
|
||||
#include "number_patternstring.h"
|
||||
|
||||
void PatternStringTest::runIndexedTest(int32_t index, UBool exec, const char *&name, char *) {
|
||||
void PatternStringTest::runIndexedTest(int32_t index, UBool exec, const char*& name, char*) {
|
||||
if (exec) {
|
||||
logln("TestSuite PatternStringTest: ");
|
||||
}
|
||||
TESTCASE_AUTO_BEGIN;
|
||||
TESTCASE_AUTO(testLocalized);
|
||||
TESTCASE_AUTO(testToPatternSimple);
|
||||
TESTCASE_AUTO(testExceptionOnInvalid);
|
||||
TESTCASE_AUTO(testBug13117);
|
||||
TESTCASE_AUTO_END;
|
||||
}
|
||||
|
||||
void PatternStringTest::testLocalized() {
|
||||
IcuTestErrorCode status(*this, "testLocalized");
|
||||
DecimalFormatSymbols symbols(Locale::getEnglish(), status);
|
||||
symbols.setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, u"a", status);
|
||||
symbols.setSymbol(DecimalFormatSymbols::kPercentSymbol, u"b", status);
|
||||
symbols.setSymbol(DecimalFormatSymbols::kMinusSignSymbol, u".", status);
|
||||
symbols.setSymbol(DecimalFormatSymbols::kPlusSignSymbol, u"'", status);
|
||||
|
||||
UnicodeString standard = u"+-abcb''a''#,##0.0%'a%'";
|
||||
UnicodeString localized = u"’.'ab'c'b''a'''#,##0a0b'a%'";
|
||||
UnicodeString toStandard = u"+-'ab'c'b''a'''#,##0.0%'a%'";
|
||||
|
||||
assertEquals(
|
||||
"standard to localized",
|
||||
localized,
|
||||
PatternStringUtils::convertLocalized(standard, symbols, true, status));
|
||||
assertEquals(
|
||||
"localized to standard",
|
||||
toStandard,
|
||||
PatternStringUtils::convertLocalized(localized, symbols, false, status));
|
||||
}
|
||||
|
||||
void PatternStringTest::testToPatternSimple() {
|
||||
const char16_t *cases[][2] = {{u"#", u"0"},
|
||||
const char16_t* cases[][2] = {{u"#", u"0"},
|
||||
{u"0", u"0"},
|
||||
{u"#0", u"0"},
|
||||
{u"###", u"0"},
|
||||
@ -42,12 +65,12 @@ void PatternStringTest::testToPatternSimple() {
|
||||
{u"*'நி'##0", u"*'நி'##0"},};
|
||||
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
for (const char16_t **cas : cases) {
|
||||
for (const char16_t** cas : cases) {
|
||||
UnicodeString input(cas[0]);
|
||||
UnicodeString output(cas[1]);
|
||||
|
||||
DecimalFormatProperties properties = PatternParser::parseToProperties(
|
||||
input, PatternParser::IGNORE_ROUNDING_NEVER, status);
|
||||
input, IGNORE_ROUNDING_NEVER, status);
|
||||
assertSuccess(input, status);
|
||||
UnicodeString actual = PatternStringUtils::propertiesToPatternString(properties, status);
|
||||
assertEquals(input, output, actual);
|
||||
@ -55,7 +78,7 @@ void PatternStringTest::testToPatternSimple() {
|
||||
}
|
||||
|
||||
void PatternStringTest::testExceptionOnInvalid() {
|
||||
static const char16_t *invalidPatterns[] = {
|
||||
static const char16_t* invalidPatterns[] = {
|
||||
u"#.#.#",
|
||||
u"0#",
|
||||
u"0#.",
|
||||
@ -80,13 +103,9 @@ void PatternStringTest::testExceptionOnInvalid() {
|
||||
void PatternStringTest::testBug13117() {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
DecimalFormatProperties expected = PatternParser::parseToProperties(
|
||||
u"0",
|
||||
PatternParser::IGNORE_ROUNDING_NEVER,
|
||||
status);
|
||||
u"0", IGNORE_ROUNDING_NEVER, status);
|
||||
DecimalFormatProperties actual = PatternParser::parseToProperties(
|
||||
u"0;",
|
||||
PatternParser::IGNORE_ROUNDING_NEVER,
|
||||
status);
|
||||
u"0;", IGNORE_ROUNDING_NEVER, status);
|
||||
assertSuccess("Spot 1", status);
|
||||
assertTrue("Should not consume negative subpattern", expected == actual);
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ void UniSetsTest::testSetCoverage() {
|
||||
const UnicodeSet &minusSign = *get(unisets::MINUS_SIGN);
|
||||
const UnicodeSet &percent = *get(unisets::PERCENT_SIGN);
|
||||
const UnicodeSet &permille = *get(unisets::PERMILLE_SIGN);
|
||||
const UnicodeSet &infinity = *get(unisets::INFINITY);
|
||||
const UnicodeSet &infinity = *get(unisets::INFINITY_KEY);
|
||||
const UnicodeSet &nanLead = *get(unisets::NAN_LEAD);
|
||||
const UnicodeSet &scientificLead = *get(unisets::SCIENTIFIC_LEAD);
|
||||
|
||||
|
@ -1956,7 +1956,10 @@ public class DecimalFormat extends NumberFormat {
|
||||
*/
|
||||
@Deprecated
|
||||
public synchronized int getMinimumGroupingDigits() {
|
||||
return properties.getMinimumGroupingDigits();
|
||||
if (properties.getMinimumGroupingDigits() > 0) {
|
||||
return properties.getMinimumGroupingDigits();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user