mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-13 08:53:20 +00:00
ICU-2825 add support for formatting and parsing currency amounts
X-SVN-Rev: 14978
This commit is contained in:
parent
894fb68198
commit
9cca22e331
6 changed files with 384 additions and 78 deletions
|
@ -1187,8 +1187,39 @@ DecimalFormat::parse(const UnicodeString& text,
|
|||
void
|
||||
DecimalFormat::parse(const UnicodeString& text,
|
||||
Formattable& result,
|
||||
ParsePosition& parsePosition) const
|
||||
{
|
||||
ParsePosition& parsePosition) const {
|
||||
parse(text, result, parsePosition, FALSE);
|
||||
}
|
||||
|
||||
Formattable& DecimalFormat::parseCurrency(const UnicodeString& text,
|
||||
Formattable& result,
|
||||
ParsePosition& pos) const {
|
||||
parse(text, result, pos, TRUE);
|
||||
return result;
|
||||
}
|
||||
|
||||
Formattable& DecimalFormat::parseCurrency(const UnicodeString& text,
|
||||
Formattable& result,
|
||||
UErrorCode& status) const {
|
||||
return NumberFormat::parseCurrency(text, result, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given text as either a number or a currency amount.
|
||||
* @param text the string to parse
|
||||
* @param result output parameter for the result
|
||||
* @param parsePosition input-output position; on input, the
|
||||
* position within text to match; must have 0 <= pos.getIndex() <
|
||||
* text.length(); on output, the position after the last matched
|
||||
* character. If the parse fails, the position in unchanged upon
|
||||
* output.
|
||||
* @param parseCurrency if true, a currency amount is parsed;
|
||||
* otherwise a Number is parsed
|
||||
*/
|
||||
void DecimalFormat::parse(const UnicodeString& text,
|
||||
Formattable& result,
|
||||
ParsePosition& parsePosition,
|
||||
UBool parseCurrency) const {
|
||||
int32_t backup;
|
||||
int32_t i = backup = parsePosition.getIndex();
|
||||
|
||||
|
@ -1219,13 +1250,19 @@ DecimalFormat::parse(const UnicodeString& text,
|
|||
|
||||
// status is used to record whether a number is infinite.
|
||||
UBool status[fgStatusLength];
|
||||
UChar curbuf[4];
|
||||
UChar* currency = parseCurrency ? curbuf : NULL;
|
||||
DigitList digits;
|
||||
|
||||
if (!subparse(text, parsePosition, digits, status)) {
|
||||
if (!subparse(text, parsePosition, digits, status, currency)) {
|
||||
parsePosition.setIndex(backup);
|
||||
return;
|
||||
}
|
||||
|
||||
if (parseCurrency) {
|
||||
result.setCurrency(curbuf);
|
||||
}
|
||||
|
||||
// Handle infinity
|
||||
if (status[fgStatusInfinite]) {
|
||||
double inf = uprv_getInfinity();
|
||||
|
@ -1283,21 +1320,27 @@ DecimalFormat::parse(const UnicodeString& text,
|
|||
This is an old implimentation that was preparing for 64-bit numbers in ICU.
|
||||
It is very slow, and 64-bit numbers are not ANSI-C compatible. This code
|
||||
is here if we change our minds.
|
||||
|
||||
^^^ what is this referring to? remove? ^^^ [alan]
|
||||
*/
|
||||
|
||||
/**
|
||||
* Parse the given text into a number. The text is parsed beginning at
|
||||
* parsePosition, until an unparseable character is seen.
|
||||
* @param text The string to parse.
|
||||
* @param text the string to parse.
|
||||
* @param parsePosition The position at which to being parsing. Upon
|
||||
* return, the first unparseable character.
|
||||
* @param digits The DigitList to set to the parsed value.
|
||||
* @param isExponent If true, parse an exponent. This means no
|
||||
* infinite values and integer only. By default it's really false.
|
||||
* @param status Upon return contains boolean status flags indicating
|
||||
* return, the first unparsed character.
|
||||
* @param digits the DigitList to set to the parsed value.
|
||||
* @param status output param containing boolean status flags indicating
|
||||
* whether the value was infinite and whether it was positive.
|
||||
* @param currency return value for parsed currency, for generic
|
||||
* currency parsing mode, or NULL for normal parsing. In generic
|
||||
* currency parsing mode, any currency is parsed, not just the
|
||||
* currency that this formatter is set to.
|
||||
*/
|
||||
UBool DecimalFormat::subparse(const UnicodeString& text, ParsePosition& parsePosition,
|
||||
DigitList& digits, UBool* status) const
|
||||
DigitList& digits, UBool* status,
|
||||
UChar* currency) const
|
||||
{
|
||||
int32_t position = parsePosition.getIndex();
|
||||
int32_t oldStart = position;
|
||||
|
@ -1308,8 +1351,8 @@ UBool DecimalFormat::subparse(const UnicodeString& text, ParsePosition& parsePos
|
|||
}
|
||||
|
||||
// Match positive and negative prefixes; prefer longest match.
|
||||
int32_t posMatch = compareAffix(text, position, FALSE, TRUE);
|
||||
int32_t negMatch = compareAffix(text, position, TRUE, TRUE);
|
||||
int32_t posMatch = compareAffix(text, position, FALSE, TRUE, currency);
|
||||
int32_t negMatch = compareAffix(text, position, TRUE, TRUE, currency);
|
||||
if (posMatch >= 0 && negMatch >= 0) {
|
||||
if (posMatch > negMatch) {
|
||||
negMatch = -1;
|
||||
|
@ -1524,10 +1567,10 @@ UBool DecimalFormat::subparse(const UnicodeString& text, ParsePosition& parsePos
|
|||
|
||||
// Match positive and negative suffixes; prefer longest match.
|
||||
if (posMatch >= 0) {
|
||||
posMatch = compareAffix(text, position, FALSE, FALSE);
|
||||
posMatch = compareAffix(text, position, FALSE, FALSE, currency);
|
||||
}
|
||||
if (negMatch >= 0) {
|
||||
negMatch = compareAffix(text, position, TRUE, FALSE);
|
||||
negMatch = compareAffix(text, position, TRUE, FALSE, currency);
|
||||
}
|
||||
if (posMatch >= 0 && negMatch >= 0) {
|
||||
if (posMatch > negMatch) {
|
||||
|
@ -1585,19 +1628,24 @@ int32_t DecimalFormat::skipPadding(const UnicodeString& text, int32_t position)
|
|||
* @param pos offset into input at which to begin matching
|
||||
* @param isNegative
|
||||
* @param isPrefix
|
||||
* @param currency return value for parsed currency, for generic
|
||||
* currency parsing mode, or null for normal parsing. In generic
|
||||
* currency parsing mode, any currency is parsed, not just the
|
||||
* currency that this formatter is set to.
|
||||
* @return length of input that matches, or -1 if match failure
|
||||
*/
|
||||
int32_t DecimalFormat::compareAffix(const UnicodeString& text,
|
||||
int32_t pos,
|
||||
UBool isNegative,
|
||||
UBool isPrefix) const {
|
||||
if (fCurrencyChoice != NULL) {
|
||||
UBool isPrefix,
|
||||
UChar* currency) const {
|
||||
if (fCurrencyChoice != NULL || currency != NULL) {
|
||||
if (isPrefix) {
|
||||
return compareComplexAffix(isNegative ? *fNegPrefixPattern : *fPosPrefixPattern,
|
||||
text, pos);
|
||||
text, pos, currency);
|
||||
} else {
|
||||
return compareComplexAffix(isNegative ? *fNegSuffixPattern : *fPosSuffixPattern,
|
||||
text, pos);
|
||||
text, pos, currency);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1709,13 +1757,18 @@ int32_t DecimalFormat::skipUWhiteSpace(const UnicodeString& text, int32_t pos) {
|
|||
* @param affixPat pattern string
|
||||
* @param input input text
|
||||
* @param pos offset into input at which to begin matching
|
||||
* @param currency return value for parsed currency, for generic
|
||||
* currency parsing mode, or null for normal parsing. In generic
|
||||
* currency parsing mode, any currency is parsed, not just the
|
||||
* currency that this formatter is set to.
|
||||
* @return length of input that matches, or -1 if match failure
|
||||
*/
|
||||
int32_t DecimalFormat::compareComplexAffix(const UnicodeString& affixPat,
|
||||
const UnicodeString& text,
|
||||
int32_t pos) const {
|
||||
U_ASSERT(fCurrencyChoice != NULL);
|
||||
U_ASSERT(*getCurrency() != 0);
|
||||
int32_t pos,
|
||||
UChar* currency) const {
|
||||
U_ASSERT(currency != NULL ||
|
||||
(fCurrencyChoice != NULL && *getCurrency() != 0));
|
||||
|
||||
for (int32_t i=0; i<affixPat.length() && pos >= 0; ) {
|
||||
UChar32 c = affixPat.char32At(i);
|
||||
|
@ -1730,16 +1783,44 @@ int32_t DecimalFormat::compareComplexAffix(const UnicodeString& affixPat,
|
|||
|
||||
switch (c) {
|
||||
case kCurrencySign: {
|
||||
// If currency != null, then perform generic currency matching.
|
||||
// Otherwise, do currency choice parsing.
|
||||
UBool intl = i<affixPat.length() &&
|
||||
affixPat.char32At(i) == kCurrencySign;
|
||||
if (intl) {
|
||||
++i;
|
||||
pos = match(text, pos, getCurrency());
|
||||
} else {
|
||||
// Parse generic currency -- anything for which we
|
||||
// have a display name, or any 3-letter ISO code.
|
||||
if (currency != NULL) {
|
||||
// Try to parse display name for our locale; first
|
||||
// determine our locale.
|
||||
UErrorCode ec = U_ZERO_ERROR;
|
||||
const char* loc = getLocaleID(ULOC_VALID_LOCALE, ec);
|
||||
if (U_FAILURE(ec) || loc == NULL || *loc == 0) {
|
||||
// applyPattern has been called; use the symbols
|
||||
loc = fSymbols->getLocale().getName();
|
||||
ec = U_ZERO_ERROR;
|
||||
}
|
||||
// Delegate parse of display name => ISO code to Currency
|
||||
ParsePosition ppos(pos);
|
||||
Formattable result;
|
||||
fCurrencyChoice->parse(text, result, ppos);
|
||||
pos = (ppos.getIndex() == pos) ? -1 : ppos.getIndex();
|
||||
UChar curr[4];
|
||||
uprv_parseCurrency(loc, text, ppos, curr, ec);
|
||||
|
||||
// If parse succeeds, populate currency[0]
|
||||
if (U_SUCCESS(ec) && ppos.getIndex() != pos) {
|
||||
u_strcpy(currency, curr);
|
||||
pos = ppos.getIndex();
|
||||
} else {
|
||||
pos = -1;
|
||||
}
|
||||
} else {
|
||||
if (intl) {
|
||||
++i;
|
||||
pos = match(text, pos, getCurrency());
|
||||
} else {
|
||||
ParsePosition ppos(pos);
|
||||
Formattable result;
|
||||
fCurrencyChoice->parse(text, result, ppos);
|
||||
pos = (ppos.getIndex() == pos) ? -1 : ppos.getIndex();
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -3607,6 +3688,17 @@ void DecimalFormat::setCurrency(const UChar* theCurrency, UErrorCode& ec) {
|
|||
}
|
||||
}
|
||||
|
||||
void DecimalFormat::getEffectiveCurrency(UChar* result, UErrorCode& ec) const {
|
||||
const UChar* c = getCurrency();
|
||||
if (*c == 0) {
|
||||
const UnicodeString &intl =
|
||||
fSymbols->getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol);
|
||||
c = intl.getBuffer(); // ok for intl to go out of scope
|
||||
}
|
||||
u_strncpy(result, c, 3);
|
||||
result[3] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of fraction digits to display, or the total
|
||||
* number of digits for significant digit formats and exponential
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "unicode/dcfmtsym.h"
|
||||
#include "unicode/decimfmt.h"
|
||||
#include "unicode/ustring.h"
|
||||
#include "unicode/ucurr.h"
|
||||
#include "uhash.h"
|
||||
#include "iculserv.h"
|
||||
#include "ucln_in.h"
|
||||
|
@ -220,20 +221,41 @@ NumberFormat::format(const Formattable& obj,
|
|||
{
|
||||
if (U_FAILURE(status)) return appendTo;
|
||||
|
||||
if (obj.getType() == Formattable::kDouble) {
|
||||
return format(obj.getDouble(), appendTo, pos);
|
||||
NumberFormat* nonconst = (NumberFormat*) this;
|
||||
|
||||
UChar save[4];
|
||||
UBool setCurr = FALSE;
|
||||
const UChar *curr = obj.getCurrency(); // most commonly curr==NULL
|
||||
if (curr != NULL) {
|
||||
// getCurrency() returns a pointer to internal storage, so we
|
||||
// copy it to retain it across the call to setCurrency().
|
||||
u_strcpy(save, getCurrency());
|
||||
setCurr = (u_strcmp(curr, save) != 0);
|
||||
if (setCurr) {
|
||||
nonconst->setCurrency(curr, status);
|
||||
}
|
||||
}
|
||||
else if (obj.getType() == Formattable::kLong) {
|
||||
return format(obj.getLong(), appendTo, pos);
|
||||
}
|
||||
else if (obj.getType() == Formattable::kInt64) {
|
||||
return format(obj.getInt64(), appendTo, pos);
|
||||
}
|
||||
// can't try to format a non-numeric object
|
||||
else {
|
||||
|
||||
switch (obj.getType()) {
|
||||
case Formattable::kDouble:
|
||||
format(obj.getDouble(), appendTo, pos);
|
||||
break;
|
||||
case Formattable::kLong:
|
||||
format(obj.getLong(), appendTo, pos);
|
||||
break;
|
||||
case Formattable::kInt64:
|
||||
format(obj.getInt64(), appendTo, pos);
|
||||
break;
|
||||
default:
|
||||
status = U_INVALID_FORMAT_ERROR;
|
||||
return appendTo;
|
||||
break;
|
||||
}
|
||||
|
||||
if (setCurr) {
|
||||
UErrorCode ok = U_ZERO_ERROR;
|
||||
nonconst->setCurrency(save, ok); // always restore currency
|
||||
}
|
||||
return appendTo;
|
||||
}
|
||||
|
||||
// -------------------------------------
|
||||
|
@ -309,6 +331,36 @@ NumberFormat::parse(const UnicodeString& text,
|
|||
}
|
||||
}
|
||||
|
||||
Formattable& NumberFormat::parseCurrency(const UnicodeString& text,
|
||||
Formattable& result,
|
||||
ParsePosition& pos) const {
|
||||
// Default implementation only -- subclasses should override
|
||||
int32_t start = pos.getIndex();
|
||||
parse(text, result, pos);
|
||||
if (pos.getIndex() != start) {
|
||||
UChar curr[4];
|
||||
UErrorCode ec = U_ZERO_ERROR;
|
||||
getEffectiveCurrency(curr, ec);
|
||||
if (U_SUCCESS(ec)) {
|
||||
result.setCurrency(curr);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Formattable& NumberFormat::parseCurrency(const UnicodeString& text,
|
||||
Formattable& result,
|
||||
UErrorCode& ec) const {
|
||||
if (U_SUCCESS(ec)) {
|
||||
ParsePosition pos(0);
|
||||
parseCurrency(text, result, pos);
|
||||
if (pos.getIndex() == 0) {
|
||||
ec = U_INVALID_FORMAT_ERROR;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// -------------------------------------
|
||||
// Sets to only parse integers.
|
||||
|
||||
|
@ -716,6 +768,20 @@ const UChar* NumberFormat::getCurrency() const {
|
|||
return fCurrency;
|
||||
}
|
||||
|
||||
void NumberFormat::getEffectiveCurrency(UChar* result, UErrorCode& ec) const {
|
||||
const UChar* c = getCurrency();
|
||||
if (*c != 0) {
|
||||
u_strncpy(result, c, 3);
|
||||
result[3] = 0;
|
||||
} else {
|
||||
const char* loc = getLocaleID(ULOC_VALID_LOCALE, ec);
|
||||
if (loc == NULL) {
|
||||
loc = uloc_getDefault();
|
||||
}
|
||||
ucurr_forLocale(loc, result, 4, &ec);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------
|
||||
// Creates the NumberFormat instance of the specified style (number, currency,
|
||||
// or percent) for the desired locale.
|
||||
|
|
|
@ -868,6 +868,52 @@ public:
|
|||
Formattable& result,
|
||||
UErrorCode& status) const;
|
||||
|
||||
/**
|
||||
* Parses text from the given string as a currency amount. Unlike
|
||||
* the parse() method, this method will attempt to parse a generic
|
||||
* currency name, searching for a match of this object's locale's
|
||||
* currency display names, or for a 3-letter ISO currency code.
|
||||
* This method will fail if this format is not a currency format,
|
||||
* that is, if it does not contain the currency pattern symbol
|
||||
* (U+00A4) in its prefix or suffix.
|
||||
*
|
||||
* @param text the string to parse
|
||||
* @param result output parameter to receive result. This will have
|
||||
* its currency set to the parsed ISO currency code.
|
||||
* @param pos input-output position; on input, the position within
|
||||
* text to match; must have 0 <= pos.getIndex() < text.length();
|
||||
* on output, the position after the last matched character. If
|
||||
* the parse fails, the position in unchanged upon output.
|
||||
* @return a reference to result
|
||||
* @draft ICU 3.0
|
||||
*/
|
||||
virtual Formattable& parseCurrency(const UnicodeString& text,
|
||||
Formattable& result,
|
||||
ParsePosition& pos) const;
|
||||
|
||||
// Redeclare here, otherwise function will be hidden
|
||||
/**
|
||||
* Parses text from the beginning of the given string as a
|
||||
* currency amount. The method might not use the entire text of
|
||||
* the given string. Unlike the parse() method, this method will
|
||||
* attempt to parse a generic currency name, searching for a match
|
||||
* of this object's locale's currency display names, or for a
|
||||
* 3-letter ISO currency code. This method will fail if this
|
||||
* format is not a currency format, that is, if it does not
|
||||
* contain the currency pattern symbol (U+00A4) in its prefix or
|
||||
* suffix.
|
||||
*
|
||||
* @param text the string to parse
|
||||
* @param result output parameter to receive result. This will have
|
||||
* its currency set to the parsed ISO currency code.
|
||||
* @param status input-output error code
|
||||
* @return a reference to result
|
||||
* @draft ICU 3.0
|
||||
*/
|
||||
Formattable& parseCurrency(const UnicodeString& text,
|
||||
Formattable& result,
|
||||
UErrorCode& status) const;
|
||||
|
||||
/**
|
||||
* Returns the decimal format symbols, which is generally not changed
|
||||
* by the programmer or user.
|
||||
|
@ -1621,32 +1667,27 @@ private:
|
|||
DigitList& digits,
|
||||
UBool isInteger) const;
|
||||
|
||||
void parse(const UnicodeString& text,
|
||||
Formattable& result,
|
||||
ParsePosition& pos,
|
||||
UBool parseCurrency) const;
|
||||
|
||||
enum {
|
||||
fgStatusInfinite,
|
||||
fgStatusLength // Leave last in list.
|
||||
} StatusFlags;
|
||||
|
||||
/**
|
||||
* Parse the given text into a number. The text is parsed beginning at
|
||||
* parsePosition, until an unparseable character is seen.
|
||||
* @param text The string to parse.
|
||||
* @param parsePosition The position at which to being parsing. Upon
|
||||
* return, the first unparseable character.
|
||||
* @param digits The DigitList to set to the parsed value.
|
||||
* @param isExponent If true, parse an exponent. This means no
|
||||
* infinite values and integer only.
|
||||
* @param status Upon return contains boolean status flags indicating
|
||||
* whether the value was infinite and whether it was positive.
|
||||
*/
|
||||
UBool subparse(const UnicodeString& text, ParsePosition& parsePosition,
|
||||
DigitList& digits, UBool* status) const;
|
||||
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;
|
||||
UBool isPrefix,
|
||||
UChar* currency) const;
|
||||
|
||||
static int32_t compareSimpleAffix(const UnicodeString& affix,
|
||||
const UnicodeString& input,
|
||||
|
@ -1658,7 +1699,8 @@ private:
|
|||
|
||||
int32_t compareComplexAffix(const UnicodeString& affixPat,
|
||||
const UnicodeString& input,
|
||||
int32_t pos) const;
|
||||
int32_t pos,
|
||||
UChar* currency) const;
|
||||
|
||||
static int32_t match(const UnicodeString& text, int32_t pos, UChar32 ch);
|
||||
|
||||
|
@ -1756,6 +1798,17 @@ private:
|
|||
EPadPosition fPadPosition;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Returns the currency in effect for this formatter. Subclasses
|
||||
* should override this method as needed. Unlike getCurrency(),
|
||||
* this method should never return "".
|
||||
* @result output parameter for null-terminated result, which must
|
||||
* have a capacity of at least 4
|
||||
* @internal
|
||||
*/
|
||||
virtual void getEffectiveCurrency(UChar* result, UErrorCode& ec) const;
|
||||
|
||||
/** number of integer digits
|
||||
* @stable ICU 2.4
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) {1997-2003}, International Business Machines Corporation and others. All Rights Reserved.
|
||||
* Copyright (C) {1997-2004}, International Business Machines Corporation and others. All Rights Reserved.
|
||||
********************************************************************************
|
||||
*
|
||||
* File NUMFMT.H
|
||||
|
@ -201,8 +201,8 @@ public:
|
|||
* <P>
|
||||
* Before calling, set parse_pos.index to the offset you want to
|
||||
* start parsing at in the source. After calling, parse_pos.index
|
||||
* is the end of the text you parsed. If error occurs, index is
|
||||
* unchanged.
|
||||
* indicates the position after the successfully parsed text. If
|
||||
* an error occurs, parse_pos.index is unchanged.
|
||||
* <P>
|
||||
* When parsing, leading whitespace is discarded (with successful
|
||||
* parse), while trailing whitespace is left as is.
|
||||
|
@ -370,6 +370,51 @@ public:
|
|||
Formattable& result,
|
||||
UErrorCode& status) const;
|
||||
|
||||
/**
|
||||
* Parses text from the given string as a currency amount. Unlike
|
||||
* the parse() method, this method will attempt to parse a generic
|
||||
* currency name, searching for a match of this object's locale's
|
||||
* currency display names, or for a 3-letter ISO currency code.
|
||||
* This method will fail if this format is not a currency format,
|
||||
* that is, if it does not contain the currency pattern symbol
|
||||
* (U+00A4) in its prefix or suffix.
|
||||
*
|
||||
* @param text the string to parse
|
||||
* @param result output parameter to receive result. This will have
|
||||
* its currency set to the parsed ISO currency code.
|
||||
* @param pos input-output position; on input, the position within
|
||||
* text to match; must have 0 <= pos.getIndex() < text.length();
|
||||
* on output, the position after the last matched character. If
|
||||
* the parse fails, the position in unchanged upon output.
|
||||
* @return a reference to result
|
||||
* @draft ICU 3.0
|
||||
*/
|
||||
virtual Formattable& parseCurrency(const UnicodeString& text,
|
||||
Formattable& result,
|
||||
ParsePosition& pos) const;
|
||||
|
||||
/**
|
||||
* Parses text from the beginning of the given string as a
|
||||
* currency amount. The method might not use the entire text of
|
||||
* the given string. Unlike the parse() method, this method will
|
||||
* attempt to parse a generic currency name, searching for a match
|
||||
* of this object's locale's currency display names, or for a
|
||||
* 3-letter ISO currency code. This method will fail if this
|
||||
* format is not a currency format, that is, if it does not
|
||||
* contain the currency pattern symbol (U+00A4) in its prefix or
|
||||
* suffix.
|
||||
*
|
||||
* @param text the string to parse
|
||||
* @param result output parameter to receive result. This will have
|
||||
* its currency set to the parsed ISO currency code.
|
||||
* @param status input-output error code
|
||||
* @return a reference to result
|
||||
* @draft ICU 3.0
|
||||
*/
|
||||
Formattable& parseCurrency(const UnicodeString& text,
|
||||
Formattable& result,
|
||||
UErrorCode& status) const;
|
||||
|
||||
/**
|
||||
* Return true if this format will parse numbers as integers
|
||||
* only. For example in the English locale, with ParseIntegerOnly
|
||||
|
@ -658,18 +703,14 @@ protected:
|
|||
NumberFormat& operator=(const NumberFormat&);
|
||||
|
||||
/**
|
||||
* Sets the minimum integer digits count directly, with no range
|
||||
* pinning. For use by subclasses.
|
||||
* Returns the currency in effect for this formatter. Subclasses
|
||||
* should override this method as needed. Unlike getCurrency(),
|
||||
* this method should never return "".
|
||||
* @result output parameter for null-terminated result, which must
|
||||
* have a capacity of at least 4
|
||||
* @internal
|
||||
*/
|
||||
inline void internalSetMinimumIntegerDigits(int32_t n);
|
||||
|
||||
/**
|
||||
* Sets the maximum integer digits count directly, with no range
|
||||
* pinning. For use by subclasses.
|
||||
* @internal
|
||||
*/
|
||||
inline void internalSetMaximumIntegerDigits(int32_t n);
|
||||
virtual void getEffectiveCurrency(UChar* result, UErrorCode& ec) const;
|
||||
|
||||
private:
|
||||
static const int32_t fgMaxIntegerDigits;
|
||||
|
@ -823,14 +864,6 @@ NumberFormat::format(const Formattable& obj,
|
|||
return Format::format(obj, appendTo, status);
|
||||
}
|
||||
|
||||
inline void NumberFormat::internalSetMinimumIntegerDigits(int32_t n) {
|
||||
fMinIntegerDigits = n;
|
||||
}
|
||||
|
||||
inline void NumberFormat::internalSetMaximumIntegerDigits(int32_t n) {
|
||||
fMaxIntegerDigits = n;
|
||||
}
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
|
|
@ -1534,8 +1534,9 @@ static const char* KEYWORDS[] = {
|
|||
/*3*/ "fp:", // <pattern or '-'> <number> <exp. string> <exp. number>
|
||||
/*4*/ "rt:", // <pattern or '-'> <(exp.) number> <(exp.) string>
|
||||
/*5*/ "p:", // <pattern or '-'> <string> <exp. number>
|
||||
/*6*/ "perr:", // <pattern or '-'> <invalid string>
|
||||
/*6*/ "perr:", // <pattern or '-'> <invalid string>
|
||||
/*7*/ "pat:", // <pattern or '-'> <exp. toPattern or '-' or 'err'>
|
||||
/*8*/ "fpc:", // <pattern or '-'> <curr.amt> <exp. string> <exp. curr.amt>
|
||||
0
|
||||
};
|
||||
|
||||
|
@ -1554,6 +1555,23 @@ static int32_t keywordIndex(const UnicodeString& tok) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a CurrencyAmount using the given NumberFormat, with
|
||||
* the 'delim' character separating the number and the currency.
|
||||
*/
|
||||
static void parseCurrencyAmount(const UnicodeString& str,
|
||||
const NumberFormat& fmt,
|
||||
UChar delim,
|
||||
Formattable& result,
|
||||
UErrorCode& ec) {
|
||||
UnicodeString num, cur;
|
||||
int32_t i = str.indexOf(delim);
|
||||
str.extractBetween(0, i, num);
|
||||
str.extractBetween(i+1, INT32_MAX, cur);
|
||||
fmt.parse(num, result, ec);
|
||||
result.setCurrency(cur.getTerminatedBuffer());
|
||||
}
|
||||
|
||||
void NumberFormatTest::TestCases() {
|
||||
UErrorCode ec = U_ZERO_ERROR;
|
||||
TextFile reader("NumberFormatTestCases.txt", "UTF8", ec);
|
||||
|
@ -1591,17 +1609,18 @@ void NumberFormatTest::TestCases() {
|
|||
case 3: // fp:
|
||||
case 4: // rt:
|
||||
case 5: // p:
|
||||
case 8: // fpc:
|
||||
if (!tokens.next(tok, ec)) goto error;
|
||||
if (tok != "-") {
|
||||
pat = tok;
|
||||
delete fmt;
|
||||
fmt = new DecimalFormat(pat, new DecimalFormatSymbols(loc, ec), ec);
|
||||
if (U_FAILURE(ec)) {
|
||||
errln("FAIL: " + where + "Pattern \"" + pat + "\"");
|
||||
errln("FAIL: " + where + "Pattern \"" + pat + "\": " + u_errorName(ec));
|
||||
ec = U_ZERO_ERROR;
|
||||
if (!tokens.next(tok, ec)) goto error;
|
||||
if (!tokens.next(tok, ec)) goto error;
|
||||
if (cmd == 3) {
|
||||
if (cmd == 3 || cmd == 8) {
|
||||
if (!tokens.next(tok, ec)) goto error;
|
||||
}
|
||||
continue;
|
||||
|
@ -1633,6 +1652,36 @@ void NumberFormatTest::TestCases() {
|
|||
n, m);
|
||||
}
|
||||
}
|
||||
// fpc: <pattern or '-'> <curr.amt> <exp. string> <exp. curr.amt>
|
||||
else if (cmd == 8) {
|
||||
UnicodeString currAmt;
|
||||
if (!tokens.next(currAmt, ec)) goto error;
|
||||
if (!tokens.next(str, ec)) goto error;
|
||||
Formattable n;
|
||||
parseCurrencyAmount(currAmt, *ref, (UChar)0x2F/*'/'*/, n, ec);
|
||||
if (assertSuccess("parseCurrencyAmount", ec)) {
|
||||
UChar save[4];
|
||||
u_strcpy(save, fmt->getCurrency());
|
||||
assertEquals(where + "\"" + pat + "\".format(" + currAmt + ")",
|
||||
str, fmt->format(n, out.remove(), ec));
|
||||
assertSuccess("format", ec);
|
||||
if (u_strcmp(save, fmt->getCurrency()) != 0) {
|
||||
errln((UnicodeString)"FAIL: " + where +
|
||||
"NumberFormat.getCurrency() => " + fmt->getCurrency() +
|
||||
", expected " + save);
|
||||
}
|
||||
}
|
||||
if (!tokens.next(currAmt, ec)) goto error;
|
||||
parseCurrencyAmount(currAmt, *ref, (UChar)0x2F/*'/'*/, n, ec);
|
||||
if (assertSuccess("parseCurrencyAmount", ec)) {
|
||||
Formattable m;
|
||||
fmt->parseCurrency(str, m, ec);
|
||||
if (assertSuccess("parseCurrency", ec)) {
|
||||
assertEquals(where + "\"" + pat + "\".parse(\"" + str + "\")",
|
||||
n, m);
|
||||
}
|
||||
}
|
||||
}
|
||||
// p: <pattern or '-'> <string to parse> <exp. number>
|
||||
else {
|
||||
UnicodeString expstr;
|
||||
|
|
|
@ -70,3 +70,16 @@ pat: "@@0" err # either @ or 0, not both
|
|||
# NumberRegression/Test4140009
|
||||
rt: "" 123.456 "123.456"
|
||||
rt: "" -123.456 "-123.456"
|
||||
|
||||
# Currency
|
||||
fpc: "\u00A4 0.00" 1234.56/USD "$ 1234.56" 1234.56/USD
|
||||
fpc: - 1234.56/JPY "\u00A5 1235" 1235/JPY
|
||||
# ISO codes that overlap display names (QQQ vs. Q)
|
||||
fpc: - 123/QQQ "QQQ 123.00" 123/QQQ # QQQ is fake
|
||||
fpc: - 123/GTQ "Q 123.00" 123/GTQ
|
||||
# ChoiceFormat-based display names
|
||||
fpc: - 1/INR "Re. 1.00" 1/INR
|
||||
fpc: - 2/INR "Rs. 2.00" 2/INR
|
||||
# Display names with shared prefix (YDD vs. Y)
|
||||
fpc: - 100/YDD "YDD 100.00" 100/YDD
|
||||
fpc: - 100/CNY "Y 100.00" 100/CNY
|
||||
|
|
Loading…
Add table
Reference in a new issue