ICU-6433 from branch to trunk for API slush

X-SVN-Rev: 25399
This commit is contained in:
Xiaomei Ji 2009-02-12 22:55:29 +00:00
parent fab4ec20c8
commit 45071a142b
13 changed files with 2401 additions and 154 deletions

2
.gitattributes vendored
View file

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

View file

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

View 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

View file

@ -1222,6 +1222,14 @@
RelativePath=".\currfmt.h"
>
</File>
<File
RelativePath=".\currpinf.cpp"
>
</File>
<File
RelativePath=".\currpinf.h"
>
</File>
<File
RelativePath=".\currunit.cpp"
>

View file

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

View file

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

View 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

View file

@ -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:
/**

View file

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

View file

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

View file

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

View file

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