ICU-13634 Implementing localized pattern converter and other pieces.

X-SVN-Rev: 41104
This commit is contained in:
Shane Carr 2018-03-14 10:41:27 +00:00
parent 73fddf50d0
commit f5d2257d34
9 changed files with 266 additions and 59 deletions

View File

@ -16,7 +16,7 @@ using namespace icu::number;
using namespace icu::number::impl;
template<typename Derived>
Derived NumberFormatterSettings<Derived>::notation(const Notation &notation) 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 &notation) 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 &macros, 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;
}

View File

@ -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();
}

View File

@ -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,

View File

@ -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) {
}

View File

@ -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;

View File

@ -166,6 +166,7 @@ class PatternModifierTest : public IntlTest {
class PatternStringTest : public IntlTest {
public:
void testLocalized();
void testToPatternSimple();
void testExceptionOnInvalid();
void testBug13117();

View File

@ -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);
}

View File

@ -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);

View File

@ -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;
}
/**