From 713ce67cba1efd6eeed48d3b688ef0b1446661e5 Mon Sep 17 00:00:00 2001 From: Markus Scherer Date: Thu, 25 May 2000 01:10:55 +0000 Subject: [PATCH] ICU-176 DecimalFormatSymbols revamped for UTF-16 and graphemes X-SVN-Rev: 1489 --- icu4c/source/i18n/dcfmtsym.cpp | 114 +++++------- icu4c/source/i18n/unicode/dcfmtsym.h | 234 +++++++++++++++--------- icu4c/source/i18n/unicode/unum.h | 88 ++++++++- icu4c/source/i18n/unum.cpp | 45 +++++ icu4c/source/test/cintltst/cnumtst.c | 32 +++- icu4c/source/test/intltest/tsdcfmsy.cpp | 25 ++- 6 files changed, 369 insertions(+), 169 deletions(-) diff --git a/icu4c/source/i18n/dcfmtsym.cpp b/icu4c/source/i18n/dcfmtsym.cpp index 1478ae8261..81b9d2a4ce 100644 --- a/icu4c/source/i18n/dcfmtsym.cpp +++ b/icu4c/source/i18n/dcfmtsym.cpp @@ -37,7 +37,7 @@ const char *DecimalFormatSymbols::fgCurrencyElements="CurrencyElements"; // Because the C-compiler doesn't parse \u escape sequences, we encode the // \u last resort strings as UChar arrays. -const UChar DecimalFormatSymbols::fgLastResortPerMill[] = { 0x2030, 0 }; +const UChar DecimalFormatSymbols::fgLastResortPermill[] = { 0x2030, 0 }; const UChar DecimalFormatSymbols::fgLastResortInfinity[] = { 0x221E, 0 }; const UChar DecimalFormatSymbols::fgLastResortNaN[] = { 0xFFFD, 0 }; const UChar DecimalFormatSymbols::fgLastResortCurrency[] = { 0x00A4, 0 }; @@ -53,7 +53,7 @@ const UnicodeString DecimalFormatSymbols::fgLastResortNumberElements[] = UNICODE_STRING("#", 1), // pattern digit UNICODE_STRING("-", 1), // minus sign UNICODE_STRING("E", 1), // exponential - DecimalFormatSymbols::fgLastResortPerMill, // per mill + DecimalFormatSymbols::fgLastResortPermill, // per mill DecimalFormatSymbols::fgLastResortInfinity, // infinite DecimalFormatSymbols::fgLastResortNaN // NaN }; @@ -90,24 +90,11 @@ DecimalFormatSymbols::~DecimalFormatSymbols() // ------------------------------------- // copy constructor -DecimalFormatSymbols::DecimalFormatSymbols(const DecimalFormatSymbols &source) - : fZeroDigit(source.fZeroDigit), - fGroupingSeparator(source.fGroupingSeparator), - fDecimalSeparator(source.fDecimalSeparator), - fPercent(source.fPercent), - fPerMill(source.fPerMill), - fDigit(source.fDigit), - fPlusSign(source.fPlusSign), - fMinusSign(source.fMinusSign), - fExponential(source.fExponential), - fPatternSeparator(source.fPatternSeparator), - fInfinity(source.fInfinity), - fNaN(source.fNaN), - fCurrencySymbol(source.fCurrencySymbol), - fIntlCurrencySymbol(source.fIntlCurrencySymbol), - fMonetarySeparator(source.fMonetarySeparator), - fPadEscape(source.fPadEscape) -{ +DecimalFormatSymbols::DecimalFormatSymbols(const DecimalFormatSymbols &source) { + int i; + for(i = 0; i < (int)ENumberFormatSymbol::kCount; ++i) { + fSymbols[(ENumberFormatSymbol)i] = source.fSymbols[(ENumberFormatSymbol)i]; + } } // ------------------------------------- @@ -118,22 +105,10 @@ DecimalFormatSymbols::operator=(const DecimalFormatSymbols& rhs) { if (this != &rhs) { - fZeroDigit = rhs.fZeroDigit; - fGroupingSeparator = rhs.fGroupingSeparator; - fDecimalSeparator = rhs.fDecimalSeparator; - fPercent = rhs.fPercent; - fPerMill = rhs.fPerMill; - fDigit = rhs.fDigit; - fPlusSign = rhs.fPlusSign; - fMinusSign = rhs.fMinusSign; - fExponential = rhs.fExponential; - fPatternSeparator = rhs.fPatternSeparator; - fInfinity = rhs.fInfinity; - fNaN = rhs.fNaN; - fCurrencySymbol = rhs.fCurrencySymbol; - fIntlCurrencySymbol = rhs.fIntlCurrencySymbol; - fMonetarySeparator = rhs.fMonetarySeparator; - fPadEscape = rhs.fPadEscape; + int i; + for(i = 0; i < (int)ENumberFormatSymbol::kCount; ++i) { + fSymbols[(ENumberFormatSymbol)i] = rhs.fSymbols[(ENumberFormatSymbol)i]; + } } return *this; } @@ -143,25 +118,17 @@ DecimalFormatSymbols::operator=(const DecimalFormatSymbols& rhs) UBool DecimalFormatSymbols::operator==(const DecimalFormatSymbols& that) const { - if (this == &that) return TRUE; + if (this == &that) { + return TRUE; + } - return (fZeroDigit == that.fZeroDigit && - fGroupingSeparator == that.fGroupingSeparator && - fDecimalSeparator == that.fDecimalSeparator && - fPercent == that.fPercent && - fPerMill == that.fPerMill && - fDigit == that.fDigit && - fPlusSign == that.fPlusSign && - fMinusSign == that.fMinusSign && - fExponential == that.fExponential && - fPatternSeparator == that.fPatternSeparator && - fInfinity == that.fInfinity && - fNaN == that.fNaN && - fCurrencySymbol == that.fCurrencySymbol && - fIntlCurrencySymbol == that.fIntlCurrencySymbol && - fMonetarySeparator == that.fMonetarySeparator && - fPadEscape == that.fPadEscape - ); + int i; + for(i = 0; i < (int)ENumberFormatSymbol::kCount; ++i) { + if(fSymbols[(ENumberFormatSymbol)i] != that.fSymbols[(ENumberFormatSymbol)i]) { + return FALSE; + } + } + return TRUE; } // ------------------------------------- @@ -221,29 +188,30 @@ DecimalFormatSymbols::initialize(const Locale& locale, UErrorCode& status, void DecimalFormatSymbols::initialize(const UnicodeString* numberElements, const UnicodeString* currencyElements) { - fDecimalSeparator = numberElements[0][(UTextOffset)0]; - fGroupingSeparator = numberElements[1][(UTextOffset)0]; - fPatternSeparator = numberElements[2][(UTextOffset)0]; - fPercent = numberElements[3][(UTextOffset)0]; - fZeroDigit = numberElements[4][(UTextOffset)0]; - fDigit = numberElements[5][(UTextOffset)0]; - fPlusSign = 0x002B; // '+' Hard coded for now; get from resource later - fMinusSign = numberElements[6][(UTextOffset)0]; - fExponential = numberElements[7][(UTextOffset)0]; - fPerMill = numberElements[8][(UTextOffset)0]; - fInfinity = numberElements[9]; - fNaN = numberElements[10]; - fCurrencySymbol = currencyElements[0]; - fIntlCurrencySymbol = currencyElements[1]; - fPadEscape = 0x002A; // '*' Hard coded for now; get from resource later + fSymbols[ENumberFormatSymbol::kDecimalSeparator] = numberElements[0]; + fSymbols[ENumberFormatSymbol::kGroupingSeparator] = numberElements[1]; + fSymbols[ENumberFormatSymbol::kPatternSeparator] = numberElements[2]; + fSymbols[ENumberFormatSymbol::kPercent] = numberElements[3]; + fSymbols[ENumberFormatSymbol::kZeroDigit] = numberElements[4]; + fSymbols[ENumberFormatSymbol::kDigit] = numberElements[5]; + fSymbols[ENumberFormatSymbol::kMinusSign] = numberElements[6]; + fSymbols[ENumberFormatSymbol::kPlusSign] = (UChar)0x002b; // '+' Hard coded for now; get from resource later + fSymbols[ENumberFormatSymbol::kCurrency] = currencyElements[0]; + fSymbols[ENumberFormatSymbol::kIntlCurrency] = currencyElements[1]; // if the resource data specified the empty string as the monetary decimal // separator, that means we should just use the regular separator as the // monetary separator - if(currencyElements[2].length() == 0) - fMonetarySeparator = fDecimalSeparator; - else - fMonetarySeparator = currencyElements[2][(UTextOffset)0]; + fSymbols[ENumberFormatSymbol::kMonetarySeparator] = + currencyElements[2].length() > 0 ? + currencyElements[2] : + fSymbols[ENumberFormatSymbol::kDecimalSeparator]; + + fSymbols[ENumberFormatSymbol::kExponential] = numberElements[7]; + fSymbols[ENumberFormatSymbol::kPermill] = numberElements[8]; + fSymbols[ENumberFormatSymbol::kPadEscape] = (UChar)0x002a; // '*' Hard coded for now; get from resource later + fSymbols[ENumberFormatSymbol::kInfinity] = numberElements[9]; + fSymbols[ENumberFormatSymbol::kNaN] = numberElements[10]; } //eof diff --git a/icu4c/source/i18n/unicode/dcfmtsym.h b/icu4c/source/i18n/unicode/dcfmtsym.h index a0a2df66ec..d7a07a3246 100644 --- a/icu4c/source/i18n/unicode/dcfmtsym.h +++ b/icu4c/source/i18n/unicode/dcfmtsym.h @@ -66,6 +66,47 @@ class U_I18N_API DecimalFormatSymbols { public: + /** + * Constants for specifying a number format symbol. + * @draft + */ + enum ENumberFormatSymbol { + /** The decimal separator */ + kDecimalSeparator, + /** The grouping separator */ + kGroupingSeparator, + /** The pattern separator */ + kPatternSeparator, + /** The percent sign */ + kPercent, + /** Zero*/ + kZeroDigit, + /** Character representing a digit in the pattern */ + kDigit, + /** The minus sign */ + kMinusSign, + /** The plus sign */ + kPlusSign, + /** The currency symbol */ + kCurrency, + /** The international currency symbol */ + kIntlCurrency, + /** The monetary separator */ + kMonetarySeparator, + /** The exponential symbol */ + kExponential, + /** Per mill symbol */ + kPermill, + /** Escape padding character */ + kPadEscape, + /** Infinity symbol */ + kInfinity, + /** Nan symbol */ + kNaN, + /** count symbol constants */ + kCount + }; + /** * Create a DecimalFormatSymbols object for the given locale. * @@ -119,118 +160,134 @@ public: UBool operator!=(const DecimalFormatSymbols& other) const { return !operator==(other); } /** - * character used for zero. Different for Arabic, etc. + * Get one of the format symbols by its enum constant. + * Each symbol is stored as a string so that graphemes + * (characters with modifyer letters) can be used. * @draft */ + UnicodeString getSymbol(ENumberFormatSymbol symbol) const; + + /** + * Set one of the format symbols by its enum constant. + * Each symbol is stored as a string so that graphemes + * (characters with modifyer letters) can be used. + * @draft + */ + void setSymbol(ENumberFormatSymbol symbol, UnicodeString value); + + /** + * character used for zero. Different for Arabic, etc. + * @deprecated remove after 2000-dec-31 + */ UChar getZeroDigit(void) const; /** * character used for zero. Different for Arabic, etc. - * @draft + * @deprecated remove after 2000-dec-31 */ void setZeroDigit(UChar zeroDigit); /** * character used for thousands separator. Different for French, etc. - * @draft + * @deprecated remove after 2000-dec-31 */ UChar getGroupingSeparator(void) const; /** * character used for thousands separator. Different for French, etc. - * @draft + * @deprecated remove after 2000-dec-31 */ void setGroupingSeparator(UChar groupingSeparator); /** * character used for decimal sign. Different for French, etc. - * @draft + * @deprecated remove after 2000-dec-31 */ UChar getDecimalSeparator(void) const; /** * character used for decimal sign. Different for French, etc. - * @draft + * @deprecated remove after 2000-dec-31 */ void setDecimalSeparator(UChar decimalSeparator); /** * character used for per mill sign. Different for Arabic, etc. - * @draft + * @deprecated remove after 2000-dec-31 */ UChar getPerMill(void) const; /** * character used for per mill sign. Different for Arabic, etc. - * @draft + * @deprecated remove after 2000-dec-31 */ - void setPerMill(UChar perMill); + void setPerMill(UChar permill); /** * character used for percent sign. Different for Arabic, etc. - * @draft + * @deprecated remove after 2000-dec-31 */ UChar getPercent(void) const; /** * character used for percent sign. Different for Arabic, etc. - * @draft + * @deprecated remove after 2000-dec-31 */ void setPercent(UChar percent); /** * character used for a digit in a pattern. - * @draft + * @deprecated remove after 2000-dec-31 */ UChar getDigit(void) const; /** * character used for a digit in a pattern. - * @draft + * @deprecated remove after 2000-dec-31 */ void setDigit(UChar digit); /** * character used to separate positive and negative subpatterns * in a pattern. - * @draft + * @deprecated remove after 2000-dec-31 */ UChar getPatternSeparator(void) const; /** * character used to separate positive and negative subpatterns * in a pattern. - * @draft + * @deprecated remove after 2000-dec-31 */ void setPatternSeparator(UChar patternSeparator); /** * character used to represent infinity. Almost always left * unchanged. - * @stable + * @deprecated remove after 2000-dec-31 */ UnicodeString& getInfinity(UnicodeString& result) const; /** * character used to represent infinity. Almost always left * unchanged. - * @stable + * @deprecated remove after 2000-dec-31 */ void setInfinity(const UnicodeString& infinity); /** * character used to represent NaN. Almost always left * unchanged. - * @stable + * @deprecated remove after 2000-dec-31 */ UnicodeString& getNaN(UnicodeString& result) const; /** * character used to represent NaN. Almost always left * unchanged. - * @stable + * @deprecated remove after 2000-dec-31 */ void setNaN(const UnicodeString& NaN); /** * character used to represent plus sign - * @draft + * @deprecated remove after 2000-dec-31 */ UChar getPlusSign(void) const; /** * character used to represent plus sign - * @draft + * @deprecated remove after 2000-dec-31 */ void setPlusSign(UChar minusSign); @@ -238,60 +295,60 @@ public: * character used to represent minus sign. If no explicit * negative format is specified, one is formed by prefixing * minusSign to the positive format. - * @draft + * @deprecated remove after 2000-dec-31 */ UChar getMinusSign(void) const; /** * character used to represent minus sign. If no explicit * negative format is specified, one is formed by prefixing * minusSign to the positive format. - * @draft + * @deprecated remove after 2000-dec-31 */ void setMinusSign(UChar minusSign); /** * character used to represent exponential. Almost always left * unchanged. - * @draft + * @deprecated remove after 2000-dec-31 */ UChar getExponentialSymbol(void) const; /** * character used to represent exponential. Almost always left * unchanged. - * @draft + * @deprecated remove after 2000-dec-31 */ void setExponentialSymbol(UChar exponential); /** * The string denoting the local currency. - * @stable + * @deprecated remove after 2000-dec-31 */ UnicodeString& getCurrencySymbol(UnicodeString& result) const; /** * The string denoting the local currency. - * @stable + * @deprecated remove after 2000-dec-31 */ void setCurrencySymbol(const UnicodeString& currency); /** * The international string denoting the local currency. - * @stable + * @deprecated remove after 2000-dec-31 */ UnicodeString& getInternationalCurrencySymbol(UnicodeString& result) const; /** * The international string denoting the local currency. - * @stable + * @deprecated remove after 2000-dec-31 */ void setInternationalCurrencySymbol(const UnicodeString& currency); /** * The monetary decimal separator. - * @draft + * @deprecated remove after 2000-dec-31 */ UChar getMonetaryDecimalSeparator(void) const; /** * The monetary decimal separator. - * @draft + * @deprecated remove after 2000-dec-31 */ void setMonetaryDecimalSeparator(UChar sep); @@ -305,7 +362,7 @@ public: * @see DecimalFormat#getFormatWidth * @see DecimalFormat#getPadPosition * @see DecimalFormat#getPadCharacter - * @draft + * @deprecated remove after 2000-dec-31 */ UChar getPadEscape(void) const; @@ -318,7 +375,7 @@ public: * @see DecimalFormat#setFormatWidth * @see DecimalFormat#setPadPosition * @see DecimalFormat#setPadCharacter - * @draft + * @deprecated remove after 2000-dec-31 */ void setPadEscape(UChar c); @@ -346,37 +403,42 @@ private: static const int32_t fgCurrencyElementsLength; static const UnicodeString fgLastResortNumberElements[]; static const UnicodeString fgLastResortCurrencyElements[]; - static const UChar fgLastResortPerMill[]; + static const UChar fgLastResortPermill[]; static const UChar fgLastResortInfinity[]; static const UChar fgLastResortNaN[]; static const UChar fgLastResortCurrency[]; static const UChar fgLastResortIntlCurrency[]; - UChar fDecimalSeparator; - UChar fGroupingSeparator; - UChar fPatternSeparator; - UChar fPercent; - UChar fZeroDigit; - UChar fDigit; - UChar fPlusSign; - UChar fMinusSign; - UnicodeString fCurrencySymbol; - UnicodeString fIntlCurrencySymbol; - UChar fMonetarySeparator; - UChar fExponential; - UChar fPadEscape; - - UChar fPerMill; - UnicodeString fInfinity; - UnicodeString fNaN; + UnicodeString fSymbols[ENumberFormatSymbol::kCount]; }; + +// ------------------------------------- + +inline UnicodeString +DecimalFormatSymbols::getSymbol(ENumberFormatSymbol symbol) const { + if(symbollength>=size +* @see unum_setSymbol +* @draft +*/ +U_CAPI int32_t U_EXPORT2 +unum_getSymbol(UNumberFormat *fmt, + UNumberFormatSymbol symbol, + UChar *buffer, + int32_t size, + UErrorCode *status); + +/** +* Set a symbol associated with a UNumberFormat. +* A UNumberFormat uses symbols to represent the special locale-dependent +* characters in a number, for example the percent sign. +* @param fmt The formatter to set. +* @param symbol The UNumberFormatSymbol constant for the symbol to set +* @param value The string to set the symbol to +* @param length The length of the string, or -1 for a zero-terminated string +* @param status A pointer to an UErrorCode to receive any errors. +* @see unum_getSymbol +* @draft +*/ +U_CAPI void U_EXPORT2 +unum_setSymbol(UNumberFormat *fmt, + UNumberFormatSymbol symbol, + const UChar *value, + int32_t length, + UErrorCode *status); + #endif diff --git a/icu4c/source/i18n/unum.cpp b/icu4c/source/i18n/unum.cpp index e867c4927e..7ed637b31c 100644 --- a/icu4c/source/i18n/unum.cpp +++ b/icu4c/source/i18n/unum.cpp @@ -598,3 +598,48 @@ unum_setSymbols( UNumberFormat* fmt, ((DecimalFormat*)fmt)->adoptDecimalFormatSymbols(syms); } + +U_CAPI int32_t U_EXPORT2 +unum_getSymbol(UNumberFormat *fmt, + UNumberFormatSymbol symbol, + UChar *buffer, + int32_t size, + UErrorCode *status) { + if(status==NULL || U_FAILURE(*status)) { + return 0; + } + + if(fmt==NULL || (uint16_t)symbol>=UNUM_FORMAT_SYMBOL_COUNT) { + *status=U_ILLEGAL_ARGUMENT_ERROR; + return 0; + } + + UnicodeString s=((DecimalFormat *)fmt)->getDecimalFormatSymbols()->getSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbol); + int32_t length=s.length(); + if(buffer!=NULL && length=UNUM_FORMAT_SYMBOL_COUNT || value==NULL || length<-1) { + *status=U_ILLEGAL_ARGUMENT_ERROR; + return; + } + + DecimalFormatSymbols symbols(*((DecimalFormat *)fmt)->getDecimalFormatSymbols()); + symbols.setSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbol, + length>=0 ? UnicodeString(value, length) : UnicodeString(value)); + ((DecimalFormat *)fmt)->setDecimalFormatSymbols(symbols); +} diff --git a/icu4c/source/test/cintltst/cnumtst.c b/icu4c/source/test/cintltst/cnumtst.c index 354ae37cc0..e2ef067162 100644 --- a/icu4c/source/test/cintltst/cnumtst.c +++ b/icu4c/source/test/cintltst/cnumtst.c @@ -41,6 +41,7 @@ void TestNumberFormat() UChar prefix[5]; UChar suffix[5]; + UChar symbol[20]; int32_t resultlength; int32_t resultlengthneeded; int32_t parsepos; @@ -51,6 +52,7 @@ void TestNumberFormat() UFieldPosition pos1; UFieldPosition pos2; int32_t numlocales; + int32_t i; UNumberFormatAttribute attr; UNumberFormatSymbols symbols1, symbols2; @@ -335,12 +337,38 @@ free(result); { log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status)); } - + if(u_strcmp(result, temp1) != 0) { + log_err("Formatting failed after setting symbols - got different result\n"); + } + /*----------- */ free(result); free(temp1); - + + /* Testing unum_get/setSymbol() */ + for(i = 0; i < UNUM_FORMAT_SYMBOL_COUNT; ++i) { + symbol[0] = (UChar)(0x41 + i); + symbol[1] = (UChar)(0x61 + i); + unum_setSymbol(cur_frpattern, i, symbol, 2, &status); + if(U_FAILURE(status)) { + log_err("Error from unum_setSymbol(%d): %s\n", i, myErrorName(status)); + return; + } + } + + for(i = 0; i < UNUM_FORMAT_SYMBOL_COUNT; ++i) { + resultlength = unum_getSymbol(cur_frpattern, i, symbol, sizeof(symbol)/U_SIZEOF_UCHAR, &status); + if(U_FAILURE(status)) { + log_err("Error from unum_getSymbol(%d): %s\n", i, myErrorName(status)); + return; + } + if(resultlength != 2 || symbol[0] != 0x41 + i || symbol[1] != 0x61 + i) { + log_err("Failure in unum_getSymbol(%d): got unexpected symbol\n", i); + } + } + + /* Testing unum_getTextAttribute() and unum_setTextAttribute()*/ log_verbose("\nTesting getting and setting text attributes\n"); resultlength=5; diff --git a/icu4c/source/test/intltest/tsdcfmsy.cpp b/icu4c/source/test/intltest/tsdcfmsy.cpp index 4b544c5446..dd80644e92 100644 --- a/icu4c/source/test/intltest/tsdcfmsy.cpp +++ b/icu4c/source/test/intltest/tsdcfmsy.cpp @@ -5,10 +5,9 @@ ********************************************************************/ #include "unicode/utypes.h" -#include "tsdcfmsy.h" - #include "unicode/dcfmtsym.h" - +#include "unicode/unum.h" +#include "tsdcfmsy.h" void IntlTestDecimalFormatSymbols::runIndexedTest( int32_t index, UBool exec, char* &name, char* par ) { @@ -131,4 +130,24 @@ void IntlTestDecimalFormatSymbols::testSymbols(char *par) if(en != fr || foo != bar) { errln("ERROR: Copy Constructor or Assignment failed"); } + + // test get/setSymbol() + if(UNUM_FORMAT_SYMBOL_COUNT != DecimalFormatSymbols::ENumberFormatSymbol::kCount) { + errln("unum.h and decimfmt.h have inconsistent numbers of format symbols!"); + return; + } + + int i; + for(i = 0; i < (int)DecimalFormatSymbols::ENumberFormatSymbol::kCount; ++i) { + foo.setSymbol((DecimalFormatSymbols::ENumberFormatSymbol)i, UnicodeString((UChar32)(0x10330 + i))); + } + for(i = 0; i < (int)DecimalFormatSymbols::ENumberFormatSymbol::kCount; ++i) { + if(foo.getSymbol((DecimalFormatSymbols::ENumberFormatSymbol)i) != UnicodeString((UChar32)(0x10330 + i))) { + errln("get/setSymbol did not roundtrip, got " + + foo.getSymbol((DecimalFormatSymbols::ENumberFormatSymbol)i) + + ", expected " + + UnicodeString((UChar32)(0x10330 + i))); + } + } + }