mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-07 14:31:31 +00:00
ICU-6433 from branch to trunk for API slush
X-SVN-Rev: 25399
This commit is contained in:
parent
fab4ec20c8
commit
45071a142b
13 changed files with 2401 additions and 154 deletions
2
.gitattributes
vendored
2
.gitattributes
vendored
|
@ -139,6 +139,7 @@ icu4c/source/data/xml/rbnf/mt.xml -text
|
|||
icu4c/source/data/xml/rbnf/root.xml -text
|
||||
icu4c/source/extra/uconv/pkgdataMakefile.in -text
|
||||
icu4c/source/extra/uconv/samples/ibm-37-test.txt -text
|
||||
icu4c/source/i18n/currpinf.cpp -text
|
||||
icu4c/source/i18n/dtitv_impl.h -text
|
||||
icu4c/source/i18n/dtitvfmt.cpp -text
|
||||
icu4c/source/i18n/dtitvinf.cpp -text
|
||||
|
@ -146,6 +147,7 @@ icu4c/source/i18n/numsys.cpp -text
|
|||
icu4c/source/i18n/tmunit.cpp -text
|
||||
icu4c/source/i18n/tmutamt.cpp -text
|
||||
icu4c/source/i18n/tmutfmt.cpp -text
|
||||
icu4c/source/i18n/unicode/currpinf.h -text
|
||||
icu4c/source/i18n/unicode/dtitvfmt.h -text
|
||||
icu4c/source/i18n/unicode/dtitvinf.h -text
|
||||
icu4c/source/i18n/unicode/numsys.h -text
|
||||
|
|
|
@ -81,7 +81,7 @@ ulocdata.o measfmt.o currfmt.o curramt.o currunit.o measure.o utmscale.o \
|
|||
csdetect.o csmatch.o csr2022.o csrecog.o csrmbcs.o csrsbcs.o csrucode.o csrutf8.o inputext.o \
|
||||
wintzimpl.o windtfmt.o winnmfmt.o basictz.o dtrule.o rbtz.o tzrule.o tztrans.o vtzone.o \
|
||||
zonemeta.o zstrfmt.o plurrule.o plurfmt.o dtitvfmt.o dtitvinf.o \
|
||||
tmunit.o tmutamt.o tmutfmt.o colldata.o bmsearch.o bms.o
|
||||
tmunit.o tmutamt.o tmutfmt.o colldata.o bmsearch.o bms.o currpinf.o
|
||||
|
||||
## Header files to install
|
||||
HEADERS = $(srcdir)/unicode/*.h
|
||||
|
|
344
icu4c/source/i18n/currpinf.cpp
Normal file
344
icu4c/source/i18n/currpinf.cpp
Normal file
|
@ -0,0 +1,344 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2009, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
#include "unicode/currpinf.h"
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
|
||||
//#define CURRENCY_PLURAL_INFO_DEBUG 1
|
||||
|
||||
#ifdef CURRENCY_PLURAL_INFO_DEBUG
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
|
||||
#include "unicode/locid.h"
|
||||
#include "unicode/plurrule.h"
|
||||
#include "unicode/ures.h"
|
||||
#include "cstring.h"
|
||||
#include "hash.h"
|
||||
#include "uresimp.h"
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
U_CDECL_BEGIN
|
||||
|
||||
/**
|
||||
* @internal ICU 4.2
|
||||
*/
|
||||
static UBool U_CALLCONV ValueComparator(UHashTok val1, UHashTok val2);
|
||||
|
||||
U_CDECL_END
|
||||
|
||||
UBool
|
||||
U_CALLCONV ValueComparator(UHashTok val1, UHashTok val2) {
|
||||
const UnicodeString* affix_1 = (UnicodeString*)val1.pointer;
|
||||
const UnicodeString* affix_2 = (UnicodeString*)val2.pointer;
|
||||
return *affix_1 == *affix_2;
|
||||
}
|
||||
|
||||
//#define CURRPINF_DEBUG
|
||||
|
||||
#ifdef CURRPINF_DEBUG
|
||||
#include "stdio.h"
|
||||
#endif
|
||||
|
||||
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CurrencyPluralInfo)
|
||||
|
||||
static const UChar gDefaultCurrencyPluralPattern[] = {'0', '.', '#', '#', ' ', 0xA4, 0xA4, 0xA4, 0};
|
||||
static const UChar gTripleCurrencySign[] = {0xA4, 0xA4, 0xA4, 0};
|
||||
static const UChar gPluralCountOther[] = {0x6F, 0x74, 0x68, 0x65, 0x72, 0};
|
||||
static const UChar gPart0[] = {0x7B, 0x30, 0x7D, 0};
|
||||
static const UChar gPart1[] = {0x7B, 0x31, 0x7D, 0};
|
||||
|
||||
static const char gNumberPatternsTag[]="NumberPatterns";
|
||||
static const char gCurrUnitPtnTag[]="CurrencyUnitPatterns";
|
||||
|
||||
CurrencyPluralInfo::CurrencyPluralInfo(UErrorCode& status)
|
||||
: fPluralCountToCurrencyUnitPattern(NULL),
|
||||
fPluralRules(NULL),
|
||||
fLocale(NULL) {
|
||||
initialize(Locale::getDefault(), status);
|
||||
}
|
||||
|
||||
CurrencyPluralInfo::CurrencyPluralInfo(const Locale& locale, UErrorCode& status)
|
||||
: fPluralCountToCurrencyUnitPattern(NULL),
|
||||
fPluralRules(NULL),
|
||||
fLocale(NULL) {
|
||||
initialize(locale, status);
|
||||
}
|
||||
|
||||
CurrencyPluralInfo::CurrencyPluralInfo(const CurrencyPluralInfo& info)
|
||||
: UObject(info),
|
||||
fPluralCountToCurrencyUnitPattern(NULL),
|
||||
fPluralRules(NULL),
|
||||
fLocale(NULL) {
|
||||
*this = info;
|
||||
}
|
||||
|
||||
|
||||
CurrencyPluralInfo&
|
||||
CurrencyPluralInfo::operator=(const CurrencyPluralInfo& info) {
|
||||
if (this == &info) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
deleteHash(fPluralCountToCurrencyUnitPattern);
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
fPluralCountToCurrencyUnitPattern = initHash(status);
|
||||
copyHash(info.fPluralCountToCurrencyUnitPattern,
|
||||
fPluralCountToCurrencyUnitPattern, status);
|
||||
if ( U_FAILURE(status) ) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
delete fPluralRules;
|
||||
delete fLocale;
|
||||
if (info.fPluralRules) {
|
||||
fPluralRules = info.fPluralRules->clone();
|
||||
} else {
|
||||
fPluralRules = NULL;
|
||||
}
|
||||
if (info.fLocale) {
|
||||
fLocale = info.fLocale->clone();
|
||||
} else {
|
||||
fLocale = NULL;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
CurrencyPluralInfo::~CurrencyPluralInfo() {
|
||||
deleteHash(fPluralCountToCurrencyUnitPattern);
|
||||
fPluralCountToCurrencyUnitPattern = NULL;
|
||||
delete fPluralRules;
|
||||
delete fLocale;
|
||||
fPluralRules = NULL;
|
||||
fLocale = NULL;
|
||||
}
|
||||
|
||||
UBool
|
||||
CurrencyPluralInfo::operator==(const CurrencyPluralInfo& info) const {
|
||||
#ifdef CURRENCY_PLURAL_INFO_DEBUG
|
||||
if (*fPluralRules == *info.fPluralRules) {
|
||||
std::cout << "same plural rules\n";
|
||||
}
|
||||
if (*fLocale == *info.fLocale) {
|
||||
std::cout << "same locale\n";
|
||||
}
|
||||
if (fPluralCountToCurrencyUnitPattern->equals(*info.fPluralCountToCurrencyUnitPattern)) {
|
||||
std::cout << "same pattern\n";
|
||||
}
|
||||
#endif
|
||||
return *fPluralRules == *info.fPluralRules &&
|
||||
*fLocale == *info.fLocale &&
|
||||
fPluralCountToCurrencyUnitPattern->equals(*info.fPluralCountToCurrencyUnitPattern);
|
||||
}
|
||||
|
||||
|
||||
CurrencyPluralInfo*
|
||||
CurrencyPluralInfo::clone() const {
|
||||
return new CurrencyPluralInfo(*this);
|
||||
}
|
||||
|
||||
const PluralRules*
|
||||
CurrencyPluralInfo::getPluralRules() const {
|
||||
return fPluralRules;
|
||||
}
|
||||
|
||||
UnicodeString&
|
||||
CurrencyPluralInfo::getCurrencyPluralPattern(const UnicodeString& pluralCount,
|
||||
UnicodeString& result) const {
|
||||
const UnicodeString* currencyPluralPattern =
|
||||
(UnicodeString*)fPluralCountToCurrencyUnitPattern->get(pluralCount);
|
||||
if (currencyPluralPattern == NULL) {
|
||||
// fall back to "other"
|
||||
if (pluralCount.compare(gPluralCountOther)) {
|
||||
currencyPluralPattern =
|
||||
(UnicodeString*)fPluralCountToCurrencyUnitPattern->get(gPluralCountOther);
|
||||
}
|
||||
if (currencyPluralPattern == NULL) {
|
||||
// no currencyUnitPatterns defined,
|
||||
// fallback to predefined defult.
|
||||
// This should never happen when ICU resource files are
|
||||
// available, since currencyUnitPattern of "other" is always
|
||||
// defined in root.
|
||||
result = UnicodeString(gDefaultCurrencyPluralPattern);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
result = *currencyPluralPattern;
|
||||
return result;
|
||||
}
|
||||
|
||||
const Locale&
|
||||
CurrencyPluralInfo::getLocale() const {
|
||||
return *fLocale;
|
||||
}
|
||||
|
||||
void
|
||||
CurrencyPluralInfo::setPluralRules(const UnicodeString& ruleDescription,
|
||||
UErrorCode& status) {
|
||||
if (U_SUCCESS(status)) {
|
||||
fPluralRules = PluralRules::createRules(ruleDescription, status);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CurrencyPluralInfo::setCurrencyPluralPattern(const UnicodeString& pluralCount,
|
||||
const UnicodeString& pattern,
|
||||
UErrorCode& status) {
|
||||
if (U_SUCCESS(status)) {
|
||||
fPluralCountToCurrencyUnitPattern->put(pluralCount, new UnicodeString(pattern), status);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CurrencyPluralInfo::setLocale(const Locale& loc, UErrorCode& status) {
|
||||
initialize(loc, status);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CurrencyPluralInfo::initialize(const Locale& loc, UErrorCode& status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
delete fLocale;
|
||||
fLocale = loc.clone();
|
||||
fPluralRules = PluralRules::forLocale(loc, status);
|
||||
setupCurrencyPluralPattern(loc, status);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CurrencyPluralInfo::setupCurrencyPluralPattern(const Locale& loc, UErrorCode& status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
fPluralCountToCurrencyUnitPattern = initHash(status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
UErrorCode ec = U_ZERO_ERROR;
|
||||
UResourceBundle *rb = ures_open(NULL, loc.getName(), &ec);
|
||||
UResourceBundle *numberPatterns = ures_getByKey(rb, gNumberPatternsTag, NULL, &ec);
|
||||
int32_t ptnLen;
|
||||
// TODO: 0 to be NumberFormat::fNumberStyle
|
||||
const UChar* numberStylePattern = ures_getStringByIndex(numberPatterns, 0,
|
||||
&ptnLen, &ec);
|
||||
ures_close(numberPatterns);
|
||||
|
||||
if (U_FAILURE(ec)) {
|
||||
ures_close(rb);
|
||||
return;
|
||||
}
|
||||
|
||||
UResourceBundle *currencyRes = ures_getByKeyWithFallback(rb, gCurrUnitPtnTag, NULL, &ec);
|
||||
|
||||
StringEnumeration* keywords = fPluralRules->getKeywords(ec);
|
||||
if (U_SUCCESS(ec)) {
|
||||
const char* pluralCount;
|
||||
while ((pluralCount = keywords->next(NULL, ec)) != NULL) {
|
||||
if ( U_SUCCESS(ec) ) {
|
||||
int32_t ptnLen;
|
||||
UErrorCode err = U_ZERO_ERROR;
|
||||
const UChar* patternChars = ures_getStringByKeyWithFallback(
|
||||
currencyRes, pluralCount, &ptnLen, &err);
|
||||
if (U_SUCCESS(err) && ptnLen > 0) {
|
||||
UnicodeString* pattern = new UnicodeString(patternChars, ptnLen);
|
||||
#ifdef CURRPINF_DEBUG
|
||||
char result_1[1000];
|
||||
pattern->extract(0, pattern->length(), result_1, "UTF-8");
|
||||
printf("pluralCount: %s; pattern: %s\n", pluralCount, result_1);
|
||||
#endif
|
||||
pattern->findAndReplace(gPart0, numberStylePattern);
|
||||
pattern->findAndReplace(gPart1, gTripleCurrencySign);
|
||||
|
||||
#ifdef CURRPINF_DEBUG
|
||||
pattern->extract(0, pattern->length(), result_1, "UTF-8");
|
||||
printf("pluralCount: %s; pattern: %s\n", pluralCount, result_1);
|
||||
#endif
|
||||
|
||||
fPluralCountToCurrencyUnitPattern->put(UnicodeString(pluralCount), pattern, status);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
delete keywords;
|
||||
ures_close(currencyRes);
|
||||
ures_close(rb);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
CurrencyPluralInfo::deleteHash(Hashtable* hTable)
|
||||
{
|
||||
if ( hTable == NULL ) {
|
||||
return;
|
||||
}
|
||||
int32_t pos = -1;
|
||||
const UHashElement* element = NULL;
|
||||
while ( (element = hTable->nextElement(pos)) != NULL ) {
|
||||
const UHashTok keyTok = element->key;
|
||||
const UHashTok valueTok = element->value;
|
||||
const UnicodeString* value = (UnicodeString*)valueTok.pointer;
|
||||
delete value;
|
||||
}
|
||||
delete hTable;
|
||||
hTable = NULL;
|
||||
}
|
||||
|
||||
|
||||
Hashtable*
|
||||
CurrencyPluralInfo::initHash(UErrorCode& status) {
|
||||
if ( U_FAILURE(status) ) {
|
||||
return NULL;
|
||||
}
|
||||
Hashtable* hTable;
|
||||
if ( (hTable = new Hashtable(TRUE, status)) == NULL ) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
hTable->setValueCompartor(ValueComparator);
|
||||
return hTable;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CurrencyPluralInfo::copyHash(const Hashtable* source,
|
||||
Hashtable* target,
|
||||
UErrorCode& status) {
|
||||
if ( U_FAILURE(status) ) {
|
||||
return;
|
||||
}
|
||||
int32_t pos = -1;
|
||||
const UHashElement* element = NULL;
|
||||
if ( source ) {
|
||||
while ( (element = source->nextElement(pos)) != NULL ) {
|
||||
const UHashTok keyTok = element->key;
|
||||
const UnicodeString* key = (UnicodeString*)keyTok.pointer;
|
||||
const UHashTok valueTok = element->value;
|
||||
const UnicodeString* value = (UnicodeString*)valueTok.pointer;
|
||||
UnicodeString* copy = new UnicodeString(*value);
|
||||
target->put(UnicodeString(*key), copy, status);
|
||||
if ( U_FAILURE(status) ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load diff
|
@ -1222,6 +1222,14 @@
|
|||
RelativePath=".\currfmt.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\currpinf.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\currpinf.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\currunit.cpp"
|
||||
>
|
||||
|
|
|
@ -74,6 +74,15 @@ static const UChar gLastResortPercentPat[] = {
|
|||
static const UChar gLastResortScientificPat[] = {
|
||||
0x23, 0x45, 0x30, 0 /* "#E0" */
|
||||
};
|
||||
static const UChar gLastResortIsoCurrencyPat[] = {
|
||||
0xA4, 0xA4, 0x23, 0x30, 0x2E, 0x30, 0x30, 0x3B, 0x28, 0xA4, 0xA4, 0x23, 0x30, 0x2E, 0x30, 0x30, 0x29, 0 /* "\u00A4\u00A4#0.00;(\u00A4\u00A4#0.00)" */
|
||||
};
|
||||
static const UChar gLastResortPluralCurrencyPat[] = {
|
||||
0x23, 0x30, 0x2E, 0x30, 0x30, 0xA0, 0xA4, 0xA4, 0xA4, 0 /* "#0.00\u00A0\u00A4\u00A4\u00A4*/
|
||||
};
|
||||
|
||||
static const UChar gSingleCurrencySign[] = {0xA4, 0};
|
||||
static const UChar gDoubleCurrencySign[] = {0xA4, 0xA4, 0};
|
||||
|
||||
// If the maximum base 10 exponent were 4, then the largest number would
|
||||
// be 99,999 which has 5 digits.
|
||||
|
@ -86,7 +95,9 @@ static const UChar * const gLastResortNumberPatterns[] =
|
|||
gLastResortDecimalPat,
|
||||
gLastResortCurrencyPat,
|
||||
gLastResortPercentPat,
|
||||
gLastResortScientificPat
|
||||
gLastResortScientificPat,
|
||||
gLastResortIsoCurrencyPat,
|
||||
gLastResortPluralCurrencyPat,
|
||||
};
|
||||
|
||||
// *****************************************************************************
|
||||
|
@ -843,6 +854,8 @@ NumberFormat::makeInstance(const Locale& desiredLocale,
|
|||
// fall-through
|
||||
|
||||
case kCurrencyStyle:
|
||||
case kIsoCurrencyStyle: // do not support plural formatting here
|
||||
case kPluralCurrencyStyle:
|
||||
f = new Win32NumberFormat(desiredLocale, curr, status);
|
||||
|
||||
if (U_SUCCESS(status)) {
|
||||
|
@ -877,7 +890,7 @@ NumberFormat::makeInstance(const Locale& desiredLocale,
|
|||
else {
|
||||
// If not all the styled patterns exists for the NumberFormat in this locale,
|
||||
// sets the status code to failure and returns nil.
|
||||
if (ures_getSize(numberPatterns) < (int32_t)(sizeof(gLastResortNumberPatterns)/sizeof(gLastResortNumberPatterns[0]))) {
|
||||
if (ures_getSize(numberPatterns) < (int32_t)(sizeof(gLastResortNumberPatterns)/sizeof(gLastResortNumberPatterns[0])) -2 ) { //minus 2: ISO and plural
|
||||
status = U_INVALID_FORMAT_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
@ -886,14 +899,25 @@ NumberFormat::makeInstance(const Locale& desiredLocale,
|
|||
symbolsToAdopt = new DecimalFormatSymbols(desiredLocale, status);
|
||||
|
||||
int32_t patLen = 0;
|
||||
const UChar *patResStr = ures_getStringByIndex(numberPatterns, (int32_t)style, &patLen, &status);
|
||||
|
||||
/* for ISOCURRENCYSTYLE and PLURALCURRENCYSTYLE,
|
||||
* the pattern is the same as the pattern of CURRENCYSTYLE
|
||||
* but by replacing the single currency sign with
|
||||
* double currency sign or triple currency sign.
|
||||
*/
|
||||
int styleInNumberPattern = ((style == kIsoCurrencyStyle ||
|
||||
style == kPluralCurrencyStyle) ?
|
||||
kCurrencyStyle : style);
|
||||
|
||||
const UChar *patResStr = ures_getStringByIndex(numberPatterns, (int32_t)styleInNumberPattern, &patLen, &status);
|
||||
|
||||
// Creates the specified decimal format style of the desired locale.
|
||||
pattern.setTo(TRUE, patResStr, patLen);
|
||||
}
|
||||
if (U_FAILURE(status) || symbolsToAdopt == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
if(style==kCurrencyStyle){
|
||||
if(style==kCurrencyStyle || style == kIsoCurrencyStyle){
|
||||
const UChar* currPattern = symbolsToAdopt->getCurrencyPattern();
|
||||
if(currPattern!=NULL){
|
||||
pattern.setTo(currPattern, u_strlen(currPattern));
|
||||
|
@ -914,7 +938,16 @@ NumberFormat::makeInstance(const Locale& desiredLocale,
|
|||
r->setDefaultRuleSet(ns->getDescription(),status);
|
||||
f = (NumberFormat *) r;
|
||||
} else {
|
||||
f = new DecimalFormat(pattern, symbolsToAdopt, status);
|
||||
// replace single currency sign in the pattern with double currency sign
|
||||
// if the style is kIsoCurrencyStyle
|
||||
if (style == kIsoCurrencyStyle) {
|
||||
pattern.findAndReplace(gSingleCurrencySign, gDoubleCurrencySign);
|
||||
}
|
||||
|
||||
f = new DecimalFormat(pattern, symbolsToAdopt, style, status);
|
||||
if (U_FAILURE(status) || f == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
f->setLocaleIDs(ures_getLocaleByType(numberPatterns, ULOC_VALID_LOCALE, &status),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
**********************************************************************
|
||||
* Copyright (c) 2002-2008, International Business Machines
|
||||
* Copyright (c) 2002-2009, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
**********************************************************************
|
||||
*/
|
||||
|
@ -74,6 +74,7 @@ static const char VAR_DELIM_STR[] = "_";
|
|||
|
||||
// Tag for localized display names (symbols) of currencies
|
||||
static const char CURRENCIES[] = "Currencies";
|
||||
static const char CURRENCYPLURALS[] = "CurrencyPlurals";
|
||||
|
||||
// Marker character indicating that a display name is a ChoiceFormat
|
||||
// pattern. Strings that start with one mark are ChoiceFormat
|
||||
|
@ -544,6 +545,82 @@ ucurr_getName(const UChar* currency,
|
|||
return currency;
|
||||
}
|
||||
|
||||
U_CAPI const UChar* U_EXPORT2
|
||||
ucurr_getPluralName(const UChar* currency,
|
||||
const char* locale,
|
||||
UBool* isChoiceFormat,
|
||||
const char* pluralCount,
|
||||
int32_t* len, // fillin
|
||||
UErrorCode* ec) {
|
||||
// Look up the Currencies resource for the given locale. The
|
||||
// Currencies locale data looks like this:
|
||||
//|en {
|
||||
//| CurrencyPlurals {
|
||||
//| USD{
|
||||
//| one{"US dollar"}
|
||||
//| other{"US dollars"}
|
||||
//| }
|
||||
//| }
|
||||
//|}
|
||||
|
||||
if (U_FAILURE(*ec)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Use a separate UErrorCode here that does not propagate out of
|
||||
// this function.
|
||||
UErrorCode ec2 = U_ZERO_ERROR;
|
||||
|
||||
char loc[ULOC_FULLNAME_CAPACITY];
|
||||
uloc_getName(locale, loc, sizeof(loc), &ec2);
|
||||
if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) {
|
||||
*ec = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char buf[ISO_COUNTRY_CODE_LENGTH+1];
|
||||
myUCharsToChars(buf, currency);
|
||||
|
||||
const UChar* s = NULL;
|
||||
ec2 = U_ZERO_ERROR;
|
||||
UResourceBundle* rb = ures_open(NULL, loc, &ec2);
|
||||
|
||||
rb = ures_getByKey(rb, CURRENCYPLURALS, rb, &ec2);
|
||||
|
||||
// Fetch resource with multi-level resource inheritance fallback
|
||||
rb = ures_getByKeyWithFallback(rb, buf, rb, &ec2);
|
||||
|
||||
s = ures_getStringByKeyWithFallback(rb, pluralCount, len, &ec2);
|
||||
if (U_FAILURE(ec2)) {
|
||||
// fall back to "other"
|
||||
ec2 = U_ZERO_ERROR;
|
||||
s = ures_getStringByKeyWithFallback(rb, "other", len, &ec2);
|
||||
if (U_FAILURE(ec2)) {
|
||||
ures_close(rb);
|
||||
// fall back to long name in Currencies
|
||||
return ucurr_getName(currency, locale, UCURR_LONG_NAME,
|
||||
isChoiceFormat, len, ec);
|
||||
}
|
||||
}
|
||||
ures_close(rb);
|
||||
|
||||
// If we've succeeded we're done. Otherwise, try to fallback.
|
||||
// If that fails (because we are already at root) then exit.
|
||||
if (U_SUCCESS(ec2)) {
|
||||
if (ec2 == U_USING_DEFAULT_WARNING
|
||||
|| (ec2 == U_USING_FALLBACK_WARNING && *ec != U_USING_DEFAULT_WARNING)) {
|
||||
*ec = ec2;
|
||||
}
|
||||
U_ASSERT(s != NULL);
|
||||
return s;
|
||||
}
|
||||
|
||||
// If we fail to find a match, use the ISO 4217 code
|
||||
*len = u_strlen(currency); // Should == ISO_COUNTRY_CODE_LENGTH, but maybe not...?
|
||||
*ec = U_USING_DEFAULT_WARNING;
|
||||
return currency;
|
||||
}
|
||||
|
||||
U_CFUNC void
|
||||
uprv_parseCurrency(const char* locale,
|
||||
const U_NAMESPACE_QUALIFIER UnicodeString& text,
|
||||
|
@ -634,8 +711,39 @@ uprv_parseCurrency(const char* locale,
|
|||
iso = ures_getKey(names);
|
||||
max = len;
|
||||
}
|
||||
|
||||
// TODO: TextTrie
|
||||
s = ures_getStringByIndex(names, UCURR_LONG_NAME, &len, &ec2);
|
||||
if (len > max && text.compare(pos.getIndex(), len, s) == 0) {
|
||||
iso = ures_getKey(names);
|
||||
max = len;
|
||||
}
|
||||
|
||||
if (3 > max && text.compare(pos.getIndex(), 3, ures_getKey(names)) == 0) {
|
||||
iso = ures_getKey(names);
|
||||
max = 3;
|
||||
}
|
||||
ures_close(names);
|
||||
}
|
||||
|
||||
// try currency plurals
|
||||
UErrorCode ec3 = U_ZERO_ERROR;
|
||||
UResourceBundle* curr_p = ures_getByKey(rb, CURRENCYPLURALS, NULL, &ec3);
|
||||
n = ures_getSize(curr_p);
|
||||
for (int32_t i=0; i<n; ++i) {
|
||||
UResourceBundle* names = ures_getByIndex(curr_p, i, NULL, &ec3);
|
||||
int32_t num = ures_getSize(names);
|
||||
int32_t len;
|
||||
for (int32_t j = 0; j < num; ++j) {
|
||||
s = ures_getStringByIndex(names, j, &len, &ec3);
|
||||
if (len > max && text.compare(pos.getIndex(), len, s) == 0) {
|
||||
iso = ures_getKey(names);
|
||||
max = len;
|
||||
}
|
||||
}
|
||||
ures_close(names);
|
||||
}
|
||||
ures_close(curr_p);
|
||||
ures_close(curr);
|
||||
ures_close(rb);
|
||||
|
||||
|
@ -1136,9 +1244,9 @@ ucurr_countCurrencies(const char* locale,
|
|||
UErrorCode localStatus = U_ZERO_ERROR;
|
||||
char id[ULOC_FULLNAME_CAPACITY];
|
||||
resLen = uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus);
|
||||
|
||||
// get country or country_variant in `id'
|
||||
uint32_t variantType = idForLocale(locale, id, sizeof(id), ec);
|
||||
|
||||
if (U_FAILURE(*ec))
|
||||
{
|
||||
return 0;
|
||||
|
@ -1253,8 +1361,8 @@ ucurr_forLocaleAndDate(const char* locale,
|
|||
char id[ULOC_FULLNAME_CAPACITY];
|
||||
resLen = uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus);
|
||||
|
||||
// get country or country_variant in `id'
|
||||
uint32_t variantType = idForLocale(locale, id, sizeof(id), ec);
|
||||
// get country or country_variant in `id'
|
||||
uint32_t variantType = idForLocale(locale, id, sizeof(id), ec);
|
||||
if (U_FAILURE(*ec))
|
||||
{
|
||||
return 0;
|
||||
|
|
269
icu4c/source/i18n/unicode/currpinf.h
Normal file
269
icu4c/source/i18n/unicode/currpinf.h
Normal file
|
@ -0,0 +1,269 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2009, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
#ifndef CURRPINF_H
|
||||
#define CURRPINF_H
|
||||
|
||||
#include "unicode/utypes.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \brief C++ API: Currency Plural Information used by Decimal Format
|
||||
*/
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
|
||||
#include "unicode/unistr.h"
|
||||
|
||||
union UHashTok;
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
U_CDECL_BEGIN
|
||||
|
||||
/**
|
||||
* @internal ICU 4.2
|
||||
*/
|
||||
static UBool U_CALLCONV ValueComparator(UHashTok val1, UHashTok val2) ;
|
||||
|
||||
U_CDECL_END
|
||||
|
||||
|
||||
class Locale;
|
||||
class PluralRules;
|
||||
class Hashtable;
|
||||
|
||||
/**
|
||||
* This class represents the information needed by
|
||||
* DecimalFormat to format currency plural,
|
||||
* such as "3.00 US dollars" or "1.00 US dollar".
|
||||
* DecimalFormat creates for itself an instance of
|
||||
* CurrencyPluralInfo from its locale data.
|
||||
* If you need to change any of these symbols, you can get the
|
||||
* CurrencyPluralInfo object from your
|
||||
* DecimalFormat and modify it.
|
||||
*
|
||||
* Following are the information needed for currency plural format and parse:
|
||||
* locale information,
|
||||
* plural rule of the locale,
|
||||
* currency plural pattern of the locale.
|
||||
*
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
class U_I18N_API CurrencyPluralInfo : public UObject {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Create a CurrencyPluralInfo object for the default locale.
|
||||
* @param status output param set to success/failure code on exit
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
CurrencyPluralInfo(UErrorCode& status);
|
||||
|
||||
/**
|
||||
* Create a CurrencyPluralInfo object for the given locale.
|
||||
* @param locale the locale
|
||||
* @param status output param set to success/failure code on exit
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
CurrencyPluralInfo(const Locale& locale, UErrorCode& status);
|
||||
|
||||
/**
|
||||
* Copy constructor
|
||||
*
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
CurrencyPluralInfo(const CurrencyPluralInfo& info);
|
||||
|
||||
|
||||
/**
|
||||
* Assignment operator
|
||||
*
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
CurrencyPluralInfo& operator=(const CurrencyPluralInfo& info);
|
||||
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
virtual ~CurrencyPluralInfo();
|
||||
|
||||
|
||||
/**
|
||||
* Equal operator.
|
||||
*
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
UBool operator==(const CurrencyPluralInfo& info) const;
|
||||
|
||||
|
||||
/**
|
||||
* Not equal operator
|
||||
*
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
UBool operator!=(const CurrencyPluralInfo& info) const;
|
||||
|
||||
|
||||
/**
|
||||
* Clone
|
||||
*
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
CurrencyPluralInfo* clone() const;
|
||||
|
||||
|
||||
/**
|
||||
* Gets plural rules of this locale, used for currency plural format
|
||||
*
|
||||
* @return plural rule
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
const PluralRules* getPluralRules() const;
|
||||
|
||||
/**
|
||||
* Given a plural count, gets currency plural pattern of this locale,
|
||||
* used for currency plural format
|
||||
*
|
||||
* @param pluralCount currency plural count
|
||||
* @param result output param to receive the pattern
|
||||
* @return a currency plural pattern based on plural count
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
UnicodeString& getCurrencyPluralPattern(const UnicodeString& pluralCount,
|
||||
UnicodeString& result) const;
|
||||
|
||||
/**
|
||||
* Get locale
|
||||
*
|
||||
* @return locale
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
const Locale& getLocale() const;
|
||||
|
||||
/**
|
||||
* Set plural rules.
|
||||
* The plural rule is set when CurrencyPluralInfo
|
||||
* instance is created.
|
||||
* You can call this method to reset plural rules only if you want
|
||||
* to modify the default plural rule of the locale.
|
||||
*
|
||||
* @param ruleDescription new plural rule description
|
||||
* @param status output param set to success/failure code on exit
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
void setPluralRules(const UnicodeString& ruleDescription,
|
||||
UErrorCode& status);
|
||||
|
||||
/**
|
||||
* Set currency plural pattern.
|
||||
* The currency plural pattern is set when CurrencyPluralInfo
|
||||
* instance is created.
|
||||
* You can call this method to reset currency plural pattern only if
|
||||
* you want to modify the default currency plural pattern of the locale.
|
||||
*
|
||||
* @param pluralCount the plural count for which the currency pattern will
|
||||
* be overridden.
|
||||
* @param pattern the new currency plural pattern
|
||||
* @param status output param set to success/failure code on exit
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
void setCurrencyPluralPattern(const UnicodeString& pluralCount,
|
||||
const UnicodeString& pattern,
|
||||
UErrorCode& status);
|
||||
|
||||
/**
|
||||
* Set locale
|
||||
*
|
||||
* @param loc the new locale to set
|
||||
* @param status output param set to success/failure code on exit
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
void setLocale(const Locale& loc, UErrorCode& status);
|
||||
|
||||
/**
|
||||
* ICU "poor man's RTTI", returns a UClassID for the actual class.
|
||||
*
|
||||
* @stable ICU 2.2
|
||||
*/
|
||||
virtual UClassID getDynamicClassID() const;
|
||||
|
||||
/**
|
||||
* ICU "poor man's RTTI", returns a UClassID for this class.
|
||||
*
|
||||
* @stable ICU 2.2
|
||||
*/
|
||||
static UClassID U_EXPORT2 getStaticClassID();
|
||||
|
||||
private:
|
||||
friend class DecimalFormat;
|
||||
|
||||
void initialize(const Locale& loc, UErrorCode& status);
|
||||
|
||||
void setupCurrencyPluralPattern(const Locale& loc, UErrorCode& status);
|
||||
|
||||
/*
|
||||
* delete hash table
|
||||
*
|
||||
* @param hTable hash table to be deleted
|
||||
*/
|
||||
void deleteHash(Hashtable* hTable);
|
||||
|
||||
|
||||
/*
|
||||
* initialize hash table
|
||||
*
|
||||
* @param status output param set to success/failure code on exit
|
||||
* @return hash table initialized
|
||||
*/
|
||||
Hashtable* initHash(UErrorCode& status);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* copy hash table
|
||||
*
|
||||
* @param source the source to copy from
|
||||
* @param target the target to copy to
|
||||
*/
|
||||
void copyHash(const Hashtable* source, Hashtable* target, UErrorCode& status);
|
||||
|
||||
//-------------------- private data member ---------------------
|
||||
// map from plural count to currency plural pattern, for example
|
||||
// a plural pattern defined in "CurrencyUnitPatterns" is
|
||||
// "one{{0} {1}}", in which "one" is a plural count
|
||||
// and "{0} {1}" is a currency plural pattern".
|
||||
// The currency plural pattern saved in this mapping is the pattern
|
||||
// defined in "CurrencyUnitPattern" by replacing
|
||||
// {0} with the number format pattern,
|
||||
// and {1} with 3 currency sign.
|
||||
Hashtable* fPluralCountToCurrencyUnitPattern;
|
||||
|
||||
/*
|
||||
* The plural rule is used to format currency plural name,
|
||||
* for example: "3.00 US Dollars".
|
||||
* If there are 3 currency signs in the currency patttern,
|
||||
* the 3 currency signs will be replaced by currency plural name.
|
||||
*/
|
||||
PluralRules* fPluralRules;
|
||||
|
||||
// locale
|
||||
Locale* fLocale;
|
||||
};
|
||||
|
||||
|
||||
inline UBool
|
||||
CurrencyPluralInfo::operator!=(const CurrencyPluralInfo& info) const { return !operator==(info); }
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
||||
#endif // _CURRPINFO
|
||||
//eof
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
********************************************************************************
|
||||
* Copyright (C) 1997-2008, International Business Machines
|
||||
* Copyright (C) 1997-2009, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
********************************************************************************
|
||||
*
|
||||
|
@ -36,10 +36,29 @@
|
|||
#include "unicode/numfmt.h"
|
||||
#include "unicode/locid.h"
|
||||
|
||||
union UHashTok;
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
U_CDECL_BEGIN
|
||||
|
||||
/**
|
||||
* @internal ICU 4.2
|
||||
*/
|
||||
static UBool U_CALLCONV AffixValueComparator(UHashTok val1, UHashTok val2) ;
|
||||
|
||||
/**
|
||||
* @internal ICU 4.2
|
||||
*/
|
||||
static UBool U_CALLCONV AffixPatternValueComparator(UHashTok val1, UHashTok val2) ;
|
||||
|
||||
U_CDECL_END
|
||||
|
||||
class DigitList;
|
||||
class ChoiceFormat;
|
||||
class CurrencyPluralInfo;
|
||||
class Hashtable;
|
||||
|
||||
/**
|
||||
* DecimalFormat is a concrete subclass of NumberFormat that formats decimal
|
||||
|
@ -47,8 +66,8 @@ class ChoiceFormat;
|
|||
* and format numbers in any locale, including support for Western, Arabic, or
|
||||
* Indic digits. It also supports different flavors of numbers, including
|
||||
* integers ("123"), fixed-point numbers ("123.4"), scientific notation
|
||||
* ("1.23E4"), percentages ("12%"), and currency amounts ("$123"). All of these
|
||||
* flavors can be easily localized.
|
||||
* ("1.23E4"), percentages ("12%"), and currency amounts ("$123", "USD123",
|
||||
* "123 US dollars"). All of these flavors can be easily localized.
|
||||
*
|
||||
* <p>To obtain a NumberFormat for a specific locale (including the default
|
||||
* locale) call one of NumberFormat's factory methods such as
|
||||
|
@ -100,6 +119,27 @@ class ChoiceFormat;
|
|||
* }
|
||||
* }
|
||||
* \endcode
|
||||
* <P>
|
||||
* Another example use createInstance(style)
|
||||
* <P>
|
||||
* <pre>
|
||||
* <strong>// Print out a number using the localized number, currency,
|
||||
* // percent, scientific, integer, iso currency, and plural currency
|
||||
* // format for each locale</strong>
|
||||
* Locale* locale = new Locale("en", "US");
|
||||
* double myNumber = 1234.56;
|
||||
* UErrorCode success = U_ZERO_ERROR;
|
||||
* UnicodeString str;
|
||||
* Formattable fmtable;
|
||||
* for (int j=NumberFormat::kNumberStyle;
|
||||
* j<=NumberFormat::kPluralCurrencyStyle;
|
||||
* ++j) {
|
||||
* NumberFormat* format = NumberFormat::createInstance(locale, j, success);
|
||||
* str.remove();
|
||||
* cout << "format result " << form->format(myNumber, str) << endl;
|
||||
* format->parse(form->format(myNumber, str), fmtable, success);
|
||||
* }</pre></blockquote>
|
||||
*
|
||||
*
|
||||
* <p><strong>Patterns</strong>
|
||||
*
|
||||
|
@ -208,6 +248,8 @@ class ChoiceFormat;
|
|||
* <td>No
|
||||
* <td>Currency sign, replaced by currency symbol. If
|
||||
* doubled, replaced by international currency symbol.
|
||||
* If tripled, replaced by currency plural names, for example,
|
||||
* "US dollar" or "US dollars" for America.
|
||||
* If present in a pattern, the monetary decimal separator
|
||||
* is used instead of the decimal separator.
|
||||
* <tr valign=top bgcolor="#eeeeff">
|
||||
|
@ -322,6 +364,12 @@ class ChoiceFormat;
|
|||
*
|
||||
* <p>During parsing, grouping separators are ignored.
|
||||
*
|
||||
* <p>For currency parsing, the formatter is able to parse every currency
|
||||
* style formats no matter which style the formatter is constructed with.
|
||||
* For example, a formatter instance gotten from
|
||||
* NumberFormat.getInstance(ULocale, NumberFormat.CURRENCYSTYLE) can parse
|
||||
* formats such as "USD1.00" and "3.00 US dollars".
|
||||
*
|
||||
* <p>If parse(UnicodeString&,Formattable&,ParsePosition&)
|
||||
* fails to parse a string, it leaves the parse position unchanged.
|
||||
* The convenience method parse(UnicodeString&,Formattable&,UErrorCode&)
|
||||
|
@ -685,6 +733,23 @@ public:
|
|||
DecimalFormatSymbols* symbolsToAdopt,
|
||||
UErrorCode& status);
|
||||
|
||||
/*
|
||||
* This API is for ICU use only.
|
||||
* Create a DecimalFormat from the given pattern, symbols, and style.
|
||||
*
|
||||
* @param pattern a non-localized pattern string
|
||||
* @param symbolsToAdopt the set of symbols to be used. The caller should not
|
||||
* delete this object after making this call.
|
||||
* @param style style of decimal format, kNumberStyle etc.
|
||||
* @param status Output param set to success/failure code. If the
|
||||
* pattern is invalid this will be set to a failure code.
|
||||
* @internal ICU 4.2
|
||||
*/
|
||||
DecimalFormat( const UnicodeString& pattern,
|
||||
DecimalFormatSymbols* symbolsToAdopt,
|
||||
NumberFormat::EStyles style,
|
||||
UErrorCode& status);
|
||||
|
||||
/**
|
||||
* Create a DecimalFormat from the given pattern and symbols.
|
||||
* Use this constructor when you need to completely customize the
|
||||
|
@ -970,6 +1035,31 @@ public:
|
|||
virtual void setDecimalFormatSymbols(const DecimalFormatSymbols& symbols);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the currency plural format information,
|
||||
* which is generally not changed by the programmer or user.
|
||||
* @return desired CurrencyPluralInfo
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
virtual const CurrencyPluralInfo* getCurrencyPluralInfo(void) const;
|
||||
|
||||
/**
|
||||
* Sets the currency plural format information,
|
||||
* which is generally not changed by the programmer or user.
|
||||
* @param toAdopt CurrencyPluralInfo to be adopted.
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
virtual void adoptCurrencyPluralInfo(CurrencyPluralInfo* toAdopt);
|
||||
|
||||
/**
|
||||
* Sets the currency plural format information,
|
||||
* which is generally not changed by the programmer or user.
|
||||
* @param info Currency Plural Info.
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
virtual void setCurrencyPluralInfo(const CurrencyPluralInfo& info);
|
||||
|
||||
|
||||
/**
|
||||
* Get the positive prefix.
|
||||
*
|
||||
|
@ -1645,6 +1735,9 @@ public:
|
|||
virtual UClassID getDynamicClassID(void) const;
|
||||
|
||||
private:
|
||||
friend UBool U_CALLCONV AffixValueComparator(UHashTok val1, UHashTok val2);
|
||||
friend UBool U_CALLCONV AffixPatternValueComparator(UHashTok val1, UHashTok val2);
|
||||
|
||||
DecimalFormat(); // default constructor not implemented
|
||||
|
||||
int32_t precision(UBool isIntegral) const;
|
||||
|
@ -1682,6 +1775,31 @@ private:
|
|||
UBool localized,
|
||||
UParseError& parseError,
|
||||
UErrorCode& status);
|
||||
|
||||
/*
|
||||
* similar to applyPattern, but without re-gen affix for currency
|
||||
*/
|
||||
void applyPatternInternally(const UnicodeString& pluralCount,
|
||||
const UnicodeString& pattern,
|
||||
UBool localized,
|
||||
UParseError& parseError,
|
||||
UErrorCode& status);
|
||||
|
||||
/*
|
||||
* only apply pattern without expand affixes
|
||||
*/
|
||||
void applyPatternWithoutExpandAffix(const UnicodeString& pattern,
|
||||
UBool localized,
|
||||
UParseError& parseError,
|
||||
UErrorCode& status);
|
||||
|
||||
|
||||
/*
|
||||
* expand affixes (after apply patter) and re-compute fFormatWidth
|
||||
*/
|
||||
void expandAffixAdjustWidth(const UnicodeString* pluralCount);
|
||||
|
||||
|
||||
/**
|
||||
* Do the work of formatting a number, either a double or a long.
|
||||
*
|
||||
|
@ -1698,6 +1816,7 @@ private:
|
|||
DigitList& digits,
|
||||
UBool isInteger) const;
|
||||
|
||||
|
||||
void parse(const UnicodeString& text,
|
||||
Formattable& result,
|
||||
ParsePosition& pos,
|
||||
|
@ -1708,16 +1827,35 @@ private:
|
|||
fgStatusLength // Leave last in list.
|
||||
} StatusFlags;
|
||||
|
||||
UBool subparse(const UnicodeString& text, ParsePosition& parsePosition,
|
||||
UBool subparse(const UnicodeString& text,
|
||||
const UnicodeString* negPrefix,
|
||||
const UnicodeString* negSuffix,
|
||||
const UnicodeString* posPrefix,
|
||||
const UnicodeString* posSuffix,
|
||||
UBool currencyParsing,
|
||||
ParsePosition& parsePosition,
|
||||
DigitList& digits, UBool* status,
|
||||
UChar* currency) const;
|
||||
|
||||
// Mixed style parsing for currency.
|
||||
// It parses against the current currency pattern
|
||||
// using complex affix comparison
|
||||
// parses against the currency plural patterns using complex affix comparison,
|
||||
// and parses against the current pattern using simple affix comparison.
|
||||
UBool parseForCurrency(const UnicodeString& text,
|
||||
ParsePosition& parsePosition,
|
||||
DigitList& digits,
|
||||
UBool* status,
|
||||
UChar* currency) const;
|
||||
|
||||
int32_t skipPadding(const UnicodeString& text, int32_t position) const;
|
||||
|
||||
int32_t compareAffix(const UnicodeString& input,
|
||||
int32_t pos,
|
||||
UBool isNegative,
|
||||
UBool isPrefix,
|
||||
const UnicodeString* affixPat,
|
||||
UBool currencyParsing,
|
||||
UChar* currency) const;
|
||||
|
||||
static int32_t compareSimpleAffix(const UnicodeString& affix,
|
||||
|
@ -1752,7 +1890,7 @@ private:
|
|||
* there are special characters. Single quotes themselves must be
|
||||
* escaped in either case.
|
||||
*/
|
||||
void appendAffixPattern(UnicodeString& appendTo, const UnicodeString& affix,
|
||||
void appendAffixPattern(UnicodeString& appendTo, const UnicodeString& affix,
|
||||
UBool localized) const;
|
||||
|
||||
void appendAffixPattern(UnicodeString& appendTo,
|
||||
|
@ -1762,9 +1900,10 @@ private:
|
|||
void expandAffix(const UnicodeString& pattern,
|
||||
UnicodeString& affix,
|
||||
double number,
|
||||
UBool doFormat) const;
|
||||
UBool doFormat,
|
||||
const UnicodeString* pluralCount) const;
|
||||
|
||||
void expandAffixes();
|
||||
void expandAffixes(const UnicodeString* pluralCount);
|
||||
|
||||
static double round(double a, ERoundingMode mode, UBool isNegative);
|
||||
|
||||
|
@ -1776,6 +1915,47 @@ private:
|
|||
|
||||
void setCurrencyForSymbols();
|
||||
|
||||
// similar to setCurrency without re-compute the affixes for currency.
|
||||
// If currency changes, the affix pattern for currency is not changed,
|
||||
// but the affix will be changed. So, affixes need to be
|
||||
// re-computed in setCurrency(), but not in setCurrencyInternally().
|
||||
virtual void setCurrencyInternally(const UChar* theCurrency, UErrorCode& ec);
|
||||
|
||||
// set up currency affix patterns for mix parsing.
|
||||
// The patterns saved here are the affix patterns of default currency
|
||||
// pattern and the unique affix patterns of the plural currency patterns.
|
||||
// Those patterns are used by parseForCurrency().
|
||||
void setupCurrencyAffixPatterns(UErrorCode& status);
|
||||
|
||||
// set up the currency affixes used in currency plural formatting.
|
||||
// It sets up both fAffixesForCurrency for currency pattern if the current
|
||||
// pattern contains 3 currency signs,
|
||||
// and it sets up fPluralAffixesForCurrency for currency plural patterns.
|
||||
void setupCurrencyAffixes(const UnicodeString& pattern,
|
||||
UBool setupForCurrentPattern,
|
||||
UBool setupForPluralPattern,
|
||||
UErrorCode& status);
|
||||
|
||||
// hashtable operations
|
||||
Hashtable* initHashForAffixPattern(UErrorCode& status);
|
||||
Hashtable* initHashForAffix(UErrorCode& status);
|
||||
|
||||
void deleteHashForAffixPattern();
|
||||
void deleteHashForAffix(Hashtable*& table);
|
||||
|
||||
void copyHashForAffixPattern(const Hashtable* source,
|
||||
Hashtable* target, UErrorCode& status);
|
||||
void copyHashForAffix(const Hashtable* source,
|
||||
Hashtable* target, UErrorCode& status);
|
||||
|
||||
// currency sign count
|
||||
enum {
|
||||
fgCurrencySignCountZero,
|
||||
fgCurrencySignCountInSymbolFormat,
|
||||
fgCurrencySignCountInISOFormat,
|
||||
fgCurrencySignCountInPluralFormat
|
||||
} CurrencySignCount;
|
||||
|
||||
/**
|
||||
* Constants.
|
||||
*/
|
||||
|
@ -1803,7 +1983,6 @@ private:
|
|||
int32_t fGroupingSize;
|
||||
int32_t fGroupingSize2;
|
||||
UBool fDecimalSeparatorAlwaysShown;
|
||||
/*transient*/ UBool fIsCurrencyFormat;
|
||||
DecimalFormatSymbols* fSymbols;
|
||||
|
||||
UBool fUseSignificantDigits;
|
||||
|
@ -1826,6 +2005,110 @@ private:
|
|||
int32_t fFormatWidth;
|
||||
EPadPosition fPadPosition;
|
||||
|
||||
/*
|
||||
* Following are used for currency format
|
||||
*/
|
||||
// pattern used in this formatter
|
||||
UnicodeString fFormatPattern;
|
||||
// style is only valid when decimal formatter is constructed by
|
||||
// DecimalFormat(pattern, decimalFormatSymbol, style)
|
||||
int fStyle;
|
||||
/*
|
||||
* Represents whether this is a currency format, and which
|
||||
* currency format style.
|
||||
* 0: not currency format type;
|
||||
* 1: currency style -- symbol name, such as "$" for US dollar.
|
||||
* 2: currency style -- ISO name, such as USD for US dollar.
|
||||
* 3: currency style -- plural long name, such as "US Dollar" for
|
||||
* "1.00 US Dollar", or "US Dollars" for
|
||||
* "3.00 US Dollars".
|
||||
*/
|
||||
int fCurrencySignCount;
|
||||
|
||||
|
||||
/* For currency parsing purose,
|
||||
* Need to remember all prefix patterns and suffix patterns of
|
||||
* every currency format pattern,
|
||||
* including the pattern of default currecny style
|
||||
* and plural currency style. And the patterns are set through applyPattern.
|
||||
*/
|
||||
// TODO: innerclass?
|
||||
struct AffixPatternsForCurrency : public UMemory {
|
||||
// negative prefix pattern
|
||||
UnicodeString negPrefixPatternForCurrency;
|
||||
// negative suffix pattern
|
||||
UnicodeString negSuffixPatternForCurrency;
|
||||
// positive prefix pattern
|
||||
UnicodeString posPrefixPatternForCurrency;
|
||||
// positive suffix pattern
|
||||
UnicodeString posSuffixPatternForCurrency;
|
||||
|
||||
AffixPatternsForCurrency(const UnicodeString& negPrefix,
|
||||
const UnicodeString& negSuffix,
|
||||
const UnicodeString& posPrefix,
|
||||
const UnicodeString& posSuffix) {
|
||||
negPrefixPatternForCurrency = negPrefix;
|
||||
negSuffixPatternForCurrency = negSuffix;
|
||||
posPrefixPatternForCurrency = posPrefix;
|
||||
posSuffixPatternForCurrency = posSuffix;
|
||||
}
|
||||
};
|
||||
|
||||
/* affix for currency formatting when the currency sign in the pattern
|
||||
* equals to 3, such as the pattern contains 3 currency sign or
|
||||
* the formatter style is currency plural format style.
|
||||
*/
|
||||
struct AffixesForCurrency : public UMemory {
|
||||
// negative prefix
|
||||
UnicodeString negPrefixForCurrency;
|
||||
// negative suffix
|
||||
UnicodeString negSuffixForCurrency;
|
||||
// positive prefix
|
||||
UnicodeString posPrefixForCurrency;
|
||||
// positive suffix
|
||||
UnicodeString posSuffixForCurrency;
|
||||
|
||||
int32_t formatWidth;
|
||||
|
||||
AffixesForCurrency(const UnicodeString& negPrefix,
|
||||
const UnicodeString& negSuffix,
|
||||
const UnicodeString& posPrefix,
|
||||
const UnicodeString& posSuffix) {
|
||||
negPrefixForCurrency = negPrefix;
|
||||
negSuffixForCurrency = negSuffix;
|
||||
posPrefixForCurrency = posPrefix;
|
||||
posSuffixForCurrency = posSuffix;
|
||||
}
|
||||
};
|
||||
|
||||
// Affix pattern set for currency.
|
||||
// It is a set of AffixPatternsForCurrency,
|
||||
// each element of the set saves the negative prefix pattern,
|
||||
// negative suffix pattern, positive prefix pattern,
|
||||
// and positive suffix pattern of a pattern.
|
||||
// It is used for currency mixed style parsing.
|
||||
// It is actually is a set.
|
||||
// The set contains the default currency pattern from the locale,
|
||||
// and the currency plural patterns.
|
||||
// Since it is a set, it does not contain duplicated items.
|
||||
// For example, if 2 currency plural patterns are the same, only one pattern
|
||||
// is included in the set. When parsing, we do not check whether the plural
|
||||
// count match or not.
|
||||
Hashtable* fAffixPatternsForCurrency;
|
||||
|
||||
// Following 2 are affixes for currency.
|
||||
// It is a hash map from plural count to AffixesForCurrency.
|
||||
// AffixesForCurrency saves the negative prefix,
|
||||
// negative suffix, positive prefix, and positive suffix of a pattern.
|
||||
// It is used during currency formatting only when the currency sign count
|
||||
// is 3. In which case, the affixes are getting from here, not
|
||||
// from the fNegativePrefix etc.
|
||||
Hashtable* fAffixesForCurrency; // for current pattern
|
||||
Hashtable* fPluralAffixesForCurrency; // for plural pattern
|
||||
|
||||
// Information needed for DecimalFormat to format/parse currency plural.
|
||||
CurrencyPluralInfo* fCurrencyPluralInfo;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
********************************************************************************
|
||||
* Copyright (C) 1997-2006, International Business Machines Corporation and others.
|
||||
* Copyright (C) 1997-2009, International Business Machines Corporation and others.
|
||||
* All Rights Reserved.
|
||||
********************************************************************************
|
||||
*
|
||||
|
@ -107,6 +107,22 @@ class StringEnumeration;
|
|||
* to get a format for displaying percentages. With this format, a
|
||||
* fraction from 0.53 is displayed as 53%.
|
||||
* <P>
|
||||
* Starting from ICU 4.2, you can use createInstance() by passing in a 'style'
|
||||
* as parameter to get the correct instance.
|
||||
* For example,
|
||||
* use createInstance(...kNumberStyle...) to get the normal number format,
|
||||
* createInstance(...kPercentStyle...) to get a format for displaying
|
||||
* percentage,
|
||||
* createInstance(...kScientificStyle...) to get a format for displaying
|
||||
* scientific number,
|
||||
* createInstance(...kCurrencyStyle...) to get the currency number format,
|
||||
* in which the currency is represented by its symbol, for example, "$3.00".
|
||||
* createInstance(...kIsoCurrencyStyle...) to get the currency number format,
|
||||
* in which the currency is represented by its ISO code, for example "USD3.00".
|
||||
* createInstance(...kPluralCurrencyStyle...) to get the currency number format,
|
||||
* in which the currency is represented by its full name in plural format,
|
||||
* for example, "3.00 US dollars" or "1.00 US dollar".
|
||||
* <P>
|
||||
* You can also control the display of numbers with such methods as
|
||||
* getMinimumFractionDigits. If you want even more control over the
|
||||
* format or parsing, or want to give your users more control, you can
|
||||
|
@ -146,6 +162,29 @@ class StringEnumeration;
|
|||
class U_I18N_API NumberFormat : public Format {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constants for various number format styles.
|
||||
* kNumberStyle specifies a normal number style of format.
|
||||
* kCurrencyStyle specifies a currency format using currency symbol name,
|
||||
* such as in "$1.00".
|
||||
* kPercentStyle specifies a style of format to display percent.
|
||||
* kScientificStyle specifies a style of format to display scientific number.
|
||||
* kISOCurrencyStyle specifies a currency format using ISO currency code,
|
||||
* such as in "USD1.00".
|
||||
* kPluralCurrencyStyle specifies a currency format using currency plural
|
||||
* names, such as in "1.00 US dollar" and "3.00 US dollars".
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
enum EStyles {
|
||||
kNumberStyle,
|
||||
kCurrencyStyle,
|
||||
kPercentStyle,
|
||||
kScientificStyle,
|
||||
kIsoCurrencyStyle,
|
||||
kPluralCurrencyStyle,
|
||||
kStyleCount // ALWAYS LAST ENUM: number of styles
|
||||
};
|
||||
|
||||
/**
|
||||
* Alignment Field constants used to construct a FieldPosition object.
|
||||
* Signifies that the position of the integer part or fraction part of
|
||||
|
@ -444,6 +483,17 @@ public:
|
|||
static NumberFormat* U_EXPORT2 createInstance(const Locale& inLocale,
|
||||
UErrorCode&);
|
||||
|
||||
/**
|
||||
* Creates the specified decimal format style of the desired locale.
|
||||
* @param desiredLocale the given locale.
|
||||
* @param choice the given style.
|
||||
* @param success Output param filled with success/failure status.
|
||||
* @return A new NumberFormat instance.
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
static NumberFormat* U_EXPORT2 createInstance(const Locale& desiredLocale, EStyles choice, UErrorCode& success);
|
||||
|
||||
|
||||
/**
|
||||
* Returns a currency format for the current default locale.
|
||||
* @stable ICU 2.0
|
||||
|
@ -712,25 +762,6 @@ protected:
|
|||
|
||||
private:
|
||||
|
||||
enum EStyles {
|
||||
kNumberStyle,
|
||||
kCurrencyStyle,
|
||||
kPercentStyle,
|
||||
kScientificStyle,
|
||||
kStyleCount // ALWAYS LAST ENUM: number of styles
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates the specified decimal format style of the desired locale.
|
||||
* Hook for service registration, uses makeInstance directly if no services
|
||||
* registered.
|
||||
* @param desiredLocale the given locale.
|
||||
* @param choice the given style.
|
||||
* @param success Output param filled with success/failure status.
|
||||
* @return A new NumberFormat instance.
|
||||
*/
|
||||
static NumberFormat* U_EXPORT2 createInstance(const Locale& desiredLocale, EStyles choice, UErrorCode& success);
|
||||
|
||||
/**
|
||||
* Creates the specified decimal format style of the desired locale.
|
||||
* @param desiredLocale the given locale.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
**********************************************************************
|
||||
* Copyright (c) 2002-2008, International Business Machines
|
||||
* Copyright (c) 2002-2009, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
**********************************************************************
|
||||
*/
|
||||
|
@ -138,6 +138,30 @@ ucurr_getName(const UChar* currency,
|
|||
int32_t* len,
|
||||
UErrorCode* ec);
|
||||
|
||||
/**
|
||||
* Returns the plural name for the given currency in the
|
||||
* given locale. For example, the plural name for the USD
|
||||
* currency object in the en_US locale is "US dollar" or "US dollars".
|
||||
* @param currency null-terminated 3-letter ISO 4217 code
|
||||
* @param locale locale in which to display currency
|
||||
* @param isChoiceFormat fill-in set to TRUE if the returned value
|
||||
* is a ChoiceFormat pattern; otherwise it is a static string
|
||||
* @param pluralCount plural count
|
||||
* @param len fill-in parameter to receive length of result
|
||||
* @param ec error code
|
||||
* @return pointer to display string of 'len' UChars. If the resource
|
||||
* data contains no entry for 'currency', then 'currency' itself is
|
||||
* returned.
|
||||
* @draft ICU 4.2
|
||||
*/
|
||||
U_STABLE const UChar* U_EXPORT2
|
||||
ucurr_getPluralName(const UChar* currency,
|
||||
const char* locale,
|
||||
UBool* isChoiceFormat,
|
||||
const char* pluralCount,
|
||||
int32_t* len,
|
||||
UErrorCode* ec);
|
||||
|
||||
/**
|
||||
* Returns the number of the number of fraction digits that should
|
||||
* be displayed for the given currency.
|
||||
|
|
|
@ -27,8 +27,11 @@
|
|||
#include "winnmtst.h"
|
||||
#include <float.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "cstring.h"
|
||||
|
||||
static const UChar EUR[] = {69,85,82,0}; // "EUR"
|
||||
static const UChar ISO_CURRENCY_USD[] = {0x55, 0x53, 0x44, 0}; // "USD"
|
||||
|
||||
// *****************************************************************************
|
||||
// class NumberFormatTest
|
||||
|
@ -87,7 +90,11 @@ void NumberFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &n
|
|||
CASE(35,TestRounding);
|
||||
CASE(36,TestNonpositiveMultiplier);
|
||||
CASE(37,TestNumberingSystems);
|
||||
|
||||
CASE(38,TestSpaceParsing);
|
||||
CASE(39,TestMultiCurrencySign);
|
||||
CASE(40,TestCurrencyFormatForMixParsing);
|
||||
CASE(41,TestDecimalFormatCurrencyParse);
|
||||
CASE(42,TestCurrencyIsoPluralFormat);
|
||||
default: name = ""; break;
|
||||
}
|
||||
}
|
||||
|
@ -2309,6 +2316,29 @@ void NumberFormatTest::TestHost()
|
|||
#ifdef U_WINDOWS
|
||||
Win32NumberTest::testLocales(this);
|
||||
#endif
|
||||
for (NumberFormat::EStyles k = NumberFormat::kNumberStyle;
|
||||
k < NumberFormat::kStyleCount; k = (NumberFormat::EStyles)(k+1)) {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
Locale loc("en_US@compat=host");
|
||||
NumberFormat *full = NumberFormat::createInstance(loc, status);
|
||||
if (full == NULL || U_FAILURE(status)) {
|
||||
errln("FAIL: Can't create number instance for host");
|
||||
return;
|
||||
}
|
||||
UnicodeString result1;
|
||||
Formattable number(10.00);
|
||||
full->format(number, result1, status);
|
||||
if (U_FAILURE(status)) {
|
||||
errln("FAIL: Can't format for host");
|
||||
return;
|
||||
}
|
||||
Formattable formattable;
|
||||
full->parse(result1, formattable, status);
|
||||
if (U_FAILURE(status)) {
|
||||
errln("FAIL: Can't parse for host");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NumberFormatTest::TestHostClone()
|
||||
|
@ -2536,10 +2566,51 @@ void NumberFormatTest::TestNonpositiveMultiplier() {
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
NumberFormatTest::TestSpaceParsing() {
|
||||
// the data are:
|
||||
// the string to be parsed, parsed position, parsed error index
|
||||
const char* DATA[][3] = {
|
||||
{"$124", "4", "-1"},
|
||||
{"$124 $124", "4", "-1"},
|
||||
{"$124 ", "4", "-1"},
|
||||
//{"$ 124 ", "5", "-1"}, // TODO: need to handle space correctly
|
||||
//{"$\\u00A0124 ", "5", "-1"}, // TODO: need to handle space correctly
|
||||
{"$ 124 ", "0", "0"},
|
||||
{"$\\u00A0124 ", "0", "0"},
|
||||
{" $ 124 ", "0", "0"}, // TODO: need to handle space correctly
|
||||
{"124$", "0", "3"}, // TODO: need to handle space correctly
|
||||
{"124 $", "5", "-1"},
|
||||
};
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
NumberFormat* foo = NumberFormat::createCurrencyInstance(status);
|
||||
if (U_FAILURE(status)) {
|
||||
delete foo;
|
||||
return;
|
||||
}
|
||||
for (uint32_t i = 0; i < sizeof(DATA)/sizeof(DATA[0]); ++i) {
|
||||
ParsePosition parsePosition(0);
|
||||
UnicodeString stringToBeParsed = ctou(DATA[i][0]);
|
||||
int parsedPosition = atoi(DATA[i][1]);
|
||||
int errorIndex = atoi(DATA[i][2]);
|
||||
Formattable result;
|
||||
foo->parse(stringToBeParsed, result, parsePosition);
|
||||
if (parsePosition.getIndex() != parsedPosition ||
|
||||
parsePosition.getErrorIndex() != errorIndex) {
|
||||
errln("FAILED parse " + stringToBeParsed + "; wrong position, expected: (" + parsedPosition + ", " + errorIndex + "); got (" + parsePosition.getIndex() + ", " + parsePosition.getErrorIndex() + ")");
|
||||
}
|
||||
if (parsePosition.getErrorIndex() == -1 &&
|
||||
result.getType() == Formattable::kLong &&
|
||||
result.getLong() != 124) {
|
||||
errln("FAILED parse " + stringToBeParsed + "; wrong number, expect: 124, got " + result.getLong());
|
||||
}
|
||||
}
|
||||
delete foo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test using various numbering systems and numbering system keyword.
|
||||
*/
|
||||
|
||||
void NumberFormatTest::TestNumberingSystems() {
|
||||
UErrorCode ec = U_ZERO_ERROR;
|
||||
|
||||
|
@ -2576,4 +2647,286 @@ void NumberFormatTest::TestNumberingSystems() {
|
|||
delete fmt3;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NumberFormatTest::TestMultiCurrencySign() {
|
||||
const char* DATA[][6] = {
|
||||
// the fields in the following test are:
|
||||
// locale,
|
||||
// currency pattern (with negative pattern),
|
||||
// currency number to be formatted,
|
||||
// currency format using currency symbol name, such as "$" for USD,
|
||||
// currency format using currency ISO name, such as "USD",
|
||||
// currency format using plural name, such as "US dollars".
|
||||
// for US locale
|
||||
{"en_US", "\\u00A4#,##0.00;-\\u00A4#,##0.00", "1234.56", "$1,234.56", "USD1,234.56", "US dollars1,234.56"},
|
||||
{"en_US", "\\u00A4#,##0.00;-\\u00A4#,##0.00", "-1234.56", "-$1,234.56", "-USD1,234.56", "-US dollars1,234.56"},
|
||||
{"en_US", "\\u00A4#,##0.00;-\\u00A4#,##0.00", "1", "$1.00", "USD1.00", "US dollar1.00"},
|
||||
// for CHINA locale
|
||||
{"zh_CN", "\\u00A4#,##0.00;(\\u00A4#,##0.00)", "1234.56", "\\uFFE51,234.56", "CNY1,234.56", "\\u4EBA\\u6C11\\u5E011,234.56"},
|
||||
{"zh_CN", "\\u00A4#,##0.00;(\\u00A4#,##0.00)", "-1234.56", "(\\uFFE51,234.56)", "(CNY1,234.56)", "(\\u4EBA\\u6C11\\u5E011,234.56)"},
|
||||
{"zh_CN", "\\u00A4#,##0.00;(\\u00A4#,##0.00)", "1", "\\uFFE51.00", "CNY1.00", "\\u4EBA\\u6C11\\u5E011.00"}
|
||||
};
|
||||
|
||||
const UChar doubleCurrencySign[] = {0xA4, 0xA4, 0};
|
||||
UnicodeString doubleCurrencyStr(doubleCurrencySign);
|
||||
const UChar tripleCurrencySign[] = {0xA4, 0xA4, 0xA4, 0};
|
||||
UnicodeString tripleCurrencyStr(tripleCurrencySign);
|
||||
|
||||
for (uint32_t i=0; i<sizeof(DATA)/sizeof(DATA[0]); ++i) {
|
||||
const char* locale = DATA[i][0];
|
||||
UnicodeString pat = ctou(DATA[i][1]);
|
||||
double numberToBeFormat = atof(DATA[i][2]);
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
DecimalFormatSymbols* sym = new DecimalFormatSymbols(Locale(locale), status);
|
||||
if (U_FAILURE(status)) {
|
||||
delete sym;
|
||||
continue;
|
||||
}
|
||||
for (int j=1; j<=3; ++j) {
|
||||
// j represents the number of currency sign in the pattern.
|
||||
if (j == 2) {
|
||||
pat = pat.findAndReplace(ctou("\\u00A4"), doubleCurrencyStr);
|
||||
} else if (j == 3) {
|
||||
pat = pat.findAndReplace(ctou("\\u00A4\\u00A4"), tripleCurrencyStr);
|
||||
}
|
||||
|
||||
DecimalFormat* fmt = new DecimalFormat(pat, new DecimalFormatSymbols(*sym), status);
|
||||
if (U_FAILURE(status)) {
|
||||
errln("FAILED init DecimalFormat ");
|
||||
delete fmt;
|
||||
continue;
|
||||
}
|
||||
UnicodeString s;
|
||||
((NumberFormat*) fmt)->format(numberToBeFormat, s);
|
||||
// DATA[i][3] is the currency format result using a
|
||||
// single currency sign.
|
||||
// DATA[i][4] is the currency format result using
|
||||
// double currency sign.
|
||||
// DATA[i][5] is the currency format result using
|
||||
// triple currency sign.
|
||||
// DATA[i][j+2] is the currency format result using
|
||||
// 'j' number of currency sign.
|
||||
UnicodeString currencyFormatResult = ctou(DATA[i][2+j]);
|
||||
if (s.compare(currencyFormatResult)) {
|
||||
errln("FAIL format: Expected " + currencyFormatResult + "; Got " + s);
|
||||
}
|
||||
// mix style parsing
|
||||
for (int k=3; k<=5; ++k) {
|
||||
// DATA[i][3] is the currency format result using a
|
||||
// single currency sign.
|
||||
// DATA[i][4] is the currency format result using
|
||||
// double currency sign.
|
||||
// DATA[i][5] is the currency format result using
|
||||
// triple currency sign.
|
||||
UnicodeString oneCurrencyFormat = ctou(DATA[i][k]);
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
Formattable parseRes;
|
||||
fmt->parse(oneCurrencyFormat, parseRes, status);
|
||||
if (U_FAILURE(status) ||
|
||||
(parseRes.getType() == Formattable::kDouble &&
|
||||
parseRes.getDouble() != numberToBeFormat) ||
|
||||
(parseRes.getType() == Formattable::kLong &&
|
||||
parseRes.getLong() != numberToBeFormat)) {
|
||||
errln("FAILED parse " + oneCurrencyFormat);
|
||||
}
|
||||
}
|
||||
delete fmt;
|
||||
}
|
||||
delete sym;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NumberFormatTest::TestCurrencyFormatForMixParsing() {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
MeasureFormat* curFmt = MeasureFormat::createCurrencyFormat(Locale("en_US"), status);
|
||||
if (U_FAILURE(status)) {
|
||||
delete curFmt;
|
||||
return;
|
||||
}
|
||||
const char* formats[] = {
|
||||
"$1,234.56", // string to be parsed
|
||||
"USD1,234.56",
|
||||
"US dollars1,234.56",
|
||||
"1,234.56 US dollars"
|
||||
};
|
||||
for (uint32_t i = 0; i < sizeof(formats)/sizeof(formats[0]); ++i) {
|
||||
UnicodeString stringToBeParsed = ctou(formats[i]);
|
||||
Formattable result;
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
curFmt->parseObject(stringToBeParsed, result, status);
|
||||
if (U_FAILURE(status)) {
|
||||
errln("FAIL: measure format parsing");
|
||||
}
|
||||
if (result.getType() != Formattable::kObject ||
|
||||
result.getObject()->getDynamicClassID() != CurrencyAmount::getStaticClassID() ||
|
||||
((CurrencyAmount*)result.getObject())->getNumber().getDouble() != 1234.56 ||
|
||||
UnicodeString(((CurrencyAmount*)result.getObject())->getISOCurrency()).compare(ISO_CURRENCY_USD)) {
|
||||
errln("FAIL: getCurrencyFormat of default locale (en_US) failed roundtripping the number ");
|
||||
if (((CurrencyAmount*)result.getObject())->getNumber().getDouble() != 1234.56) {
|
||||
errln((UnicodeString)"wong number, expect: 1234.56" + ", got: " + ((CurrencyAmount*)result.getObject())->getNumber().getDouble());
|
||||
}
|
||||
if (((CurrencyAmount*)result.getObject())->getISOCurrency() != ISO_CURRENCY_USD) {
|
||||
errln((UnicodeString)"wong currency, expect: USD" + ", got: " + ((CurrencyAmount*)result.getObject())->getISOCurrency());
|
||||
}
|
||||
}
|
||||
}
|
||||
delete curFmt;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NumberFormatTest::TestDecimalFormatCurrencyParse() {
|
||||
// Locale.US
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
DecimalFormatSymbols* sym = new DecimalFormatSymbols(Locale("en_US"), status);
|
||||
if (U_FAILURE(status)) {
|
||||
delete sym;
|
||||
return;
|
||||
}
|
||||
UnicodeString pat;
|
||||
UChar currency = 0x00A4;
|
||||
// "\xA4#,##0.00;-\xA4#,##0.00"
|
||||
pat.append(currency).append(currency).append(currency).append("#,##0.00;-").append(currency).append(currency).append(currency).append("#,##0.00");
|
||||
DecimalFormat* fmt = new DecimalFormat(pat, sym, status);
|
||||
if (U_FAILURE(status)) {
|
||||
delete fmt;
|
||||
errln("failed to new DecimalFormat in TestDecimalFormatCurrencyParse");
|
||||
return;
|
||||
}
|
||||
const char* DATA[][2] = {
|
||||
// the data are:
|
||||
// string to be parsed, the parsed result (number)
|
||||
{"$1.00", "1"},
|
||||
{"USD1.00", "1"},
|
||||
{"1.00 US dollar", "1"},
|
||||
{"$1,234.56", "1234.56"},
|
||||
{"USD1,234.56", "1234.56"},
|
||||
{"1,234.56 US dollar", "1234.56"},
|
||||
};
|
||||
for (uint32_t i = 0; i < sizeof(DATA)/sizeof(DATA[0]); ++i) {
|
||||
UnicodeString stringToBeParsed = ctou(DATA[i][0]);
|
||||
double parsedResult = atof(DATA[i][1]);
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
Formattable result;
|
||||
fmt->parse(stringToBeParsed, result, status);
|
||||
if (U_FAILURE(status) ||
|
||||
(result.getType() == Formattable::kDouble &&
|
||||
result.getDouble() != parsedResult) ||
|
||||
(result.getType() == Formattable::kLong &&
|
||||
result.getLong() != parsedResult)) {
|
||||
errln((UnicodeString)"FAIL parse: Expected " + parsedResult);
|
||||
}
|
||||
}
|
||||
delete fmt;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NumberFormatTest::TestCurrencyIsoPluralFormat() {
|
||||
const char* DATA[][6] = {
|
||||
// the data are:
|
||||
// locale,
|
||||
// currency amount to be formatted,
|
||||
// currency ISO code to be formatted,
|
||||
// format result using CURRENCYSTYLE,
|
||||
// format result using ISOCURRENCYSTYLE,
|
||||
// format result using PLURALCURRENCYSTYLE,
|
||||
{"en_US", "1", "USD", "$1.00", "USD1.00", "1.00 US dollar"},
|
||||
{"en_US", "1234.56", "USD", "$1,234.56", "USD1,234.56", "1,234.56 US dollars"},
|
||||
{"en_US", "-1234.56", "USD", "($1,234.56)", "(USD1,234.56)", "-1,234.56 US dollars"},
|
||||
{"zh_CN", "1", "USD", "US$1.00", "USD1.00", "1.00 \\u7F8E\\u5143"},
|
||||
{"zh_CN", "1234.56", "USD", "US$1,234.56", "USD1,234.56", "1,234.56 \\u7F8E\\u5143"},
|
||||
{"zh_CN", "1", "CHY", "CHY1.00", "CHY1.00", "1.00 CHY"},
|
||||
{"zh_CN", "1234.56", "CHY", "CHY1,234.56", "CHY1,234.56", "1,234.56 CHY"},
|
||||
{"zh_CN", "1", "CNY", "\\uFFE51.00", "CNY1.00", "1.00 \\u4EBA\\u6C11\\u5E01"},
|
||||
{"zh_CN", "1234.56", "CNY", "\\uFFE51,234.56", "CNY1,234.56", "1,234.56 \\u4EBA\\u6C11\\u5E01"},
|
||||
{"ru_RU", "1", "RUB", "1,00\\u00A0\\u0440\\u0443\\u0431.", "1,00\\u00A0RUB", "1,00 \\u0420\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u0438\\u0439 \\u0440\\u0443\\u0431\\u043B\\u044C"},
|
||||
{"ru_RU", "2", "RUB", "2,00\\u00A0\\u0440\\u0443\\u0431.", "2,00\\u00A0RUB", "2,00 \\u0420\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u0438\\u0445 \\u0440\\u0443\\u0431\\u043B\\u044F"},
|
||||
{"ru_RU", "5", "RUB", "5,00\\u00A0\\u0440\\u0443\\u0431.", "5,00\\u00A0RUB", "5,00 \\u0420\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u0438\\u0445 \\u0440\\u0443\\u0431\\u043B\\u0435\\u0439"},
|
||||
// test locale without currency information
|
||||
{"ti_ET", "-1.23", "USD", "-US$1.23", "-USD1.23", "-1.23 USD"},
|
||||
// test choice format
|
||||
{"es_AR", "1", "INR", "Re.\\u00A01,00", "INR\\u00A01,00", "1,00 rupia india"},
|
||||
};
|
||||
|
||||
for (uint32_t i=0; i<sizeof(DATA)/sizeof(DATA[0]); ++i) {
|
||||
for (NumberFormat::EStyles k = NumberFormat::kCurrencyStyle;
|
||||
k <= NumberFormat::kPluralCurrencyStyle;
|
||||
k = (NumberFormat::EStyles)(k+1)) {
|
||||
// k represents currency format style.
|
||||
if ( k != NumberFormat::kCurrencyStyle &&
|
||||
k != NumberFormat::kIsoCurrencyStyle &&
|
||||
k != NumberFormat::kPluralCurrencyStyle ) {
|
||||
continue;
|
||||
}
|
||||
const char* localeString = DATA[i][0];
|
||||
double numberToBeFormat = atof(DATA[i][1]);
|
||||
const char* currencyISOCode = DATA[i][2];
|
||||
Locale locale(localeString);
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
NumberFormat* numFmt = NumberFormat::createInstance(locale, k, status);
|
||||
if (U_FAILURE(status)) {
|
||||
delete numFmt;
|
||||
errln((UnicodeString)"can not create instance, locale:" + localeString + ", style: " + k);
|
||||
continue;
|
||||
}
|
||||
// TODO: need to be UChar*
|
||||
UChar currencyCode[4];
|
||||
currencyCode[0] = currencyISOCode[0];
|
||||
currencyCode[1] = currencyISOCode[1];
|
||||
currencyCode[2] = currencyISOCode[2];
|
||||
currencyCode[3] = currencyISOCode[3];
|
||||
numFmt->setCurrency(currencyCode, status);
|
||||
if (U_FAILURE(status)) {
|
||||
delete numFmt;
|
||||
errln((UnicodeString)"can not set currency:" + currencyISOCode);
|
||||
continue;
|
||||
}
|
||||
|
||||
UnicodeString strBuf;
|
||||
numFmt->format(numberToBeFormat, strBuf);
|
||||
int resultDataIndex = k;
|
||||
if ( k == NumberFormat::kCurrencyStyle ) {
|
||||
resultDataIndex = k+2;
|
||||
}
|
||||
// DATA[i][resultDataIndex] is the currency format result
|
||||
// using 'k' currency style.
|
||||
UnicodeString formatResult = ctou(DATA[i][resultDataIndex]);
|
||||
if (strBuf.compare(formatResult)) {
|
||||
errln("FAIL: Expected " + formatResult + " actual: " + strBuf);
|
||||
}
|
||||
// test parsing, and test parsing for all currency formats.
|
||||
for (int j = 3; j < 6; ++j) {
|
||||
// DATA[i][3] is the currency format result using
|
||||
// CURRENCYSTYLE formatter.
|
||||
// DATA[i][4] is the currency format result using
|
||||
// ISOCURRENCYSTYLE formatter.
|
||||
// DATA[i][5] is the currency format result using
|
||||
// PLURALCURRENCYSTYLE formatter.
|
||||
UnicodeString oneCurrencyFormatResult = ctou(DATA[i][j]);
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
Formattable parseResult;
|
||||
numFmt->parse(oneCurrencyFormatResult, parseResult, status);
|
||||
if (U_FAILURE(status) ||
|
||||
(parseResult.getType() == Formattable::kDouble &&
|
||||
parseResult.getDouble() != numberToBeFormat) ||
|
||||
(parseResult.getType() == Formattable::kLong &&
|
||||
parseResult.getLong() != numberToBeFormat)) {
|
||||
errln((UnicodeString)"FAIL: getCurrencyFormat of locale " +
|
||||
localeString + " failed roundtripping the number");
|
||||
if (parseResult.getType() == Formattable::kDouble) {
|
||||
errln((UnicodeString)"expected: " + numberToBeFormat + "; actual: " +parseResult.getDouble());
|
||||
} else {
|
||||
errln((UnicodeString)"expected: " + numberToBeFormat + "; actual: " +parseResult.getLong());
|
||||
}
|
||||
}
|
||||
}
|
||||
delete numFmt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
|
|
@ -134,6 +134,13 @@ class NumberFormatTest: public CalendarTimeZoneTest {
|
|||
|
||||
void TestNumberingSystems();
|
||||
|
||||
|
||||
void TestSpaceParsing();
|
||||
void TestMultiCurrencySign();
|
||||
void TestCurrencyFormatForMixParsing();
|
||||
void TestDecimalFormatCurrencyParse();
|
||||
void TestCurrencyIsoPluralFormat();
|
||||
|
||||
private:
|
||||
|
||||
static UBool equalValue(const Formattable& a, const Formattable& b);
|
||||
|
|
Loading…
Add table
Reference in a new issue