From 461f739085f9d970b224479102382aec8b7fd580 Mon Sep 17 00:00:00 2001 From: Alan Liu Date: Wed, 21 Apr 2004 18:05:06 +0000 Subject: [PATCH] ICU-2825 first implementation of MeasureFormat X-SVN-Rev: 15015 --- icu4c/source/i18n/currfmt.cpp | 78 ++++++++++++ icu4c/source/i18n/currfmt.h | 112 ++++++++++++++++++ icu4c/source/i18n/decimfmt.cpp | 6 - icu4c/source/i18n/i18n.vcproj | 26 ++++ icu4c/source/i18n/measfmt.cpp | 42 +++++++ icu4c/source/i18n/numfmt.cpp | 15 +-- icu4c/source/i18n/unicode/decimfmt.h | 25 +--- icu4c/source/i18n/unicode/measfmt.h | 61 ++++++++++ icu4c/source/i18n/unicode/numfmt.h | 24 +--- icu4c/source/test/intltest/numfmtst.cpp | 76 ++++++------ .../test/testdata/NumberFormatTestCases.txt | 16 +-- 11 files changed, 372 insertions(+), 109 deletions(-) create mode 100644 icu4c/source/i18n/currfmt.cpp create mode 100644 icu4c/source/i18n/currfmt.h create mode 100644 icu4c/source/i18n/measfmt.cpp create mode 100644 icu4c/source/i18n/unicode/measfmt.h diff --git a/icu4c/source/i18n/currfmt.cpp b/icu4c/source/i18n/currfmt.cpp new file mode 100644 index 00000000000..da2e6adf011 --- /dev/null +++ b/icu4c/source/i18n/currfmt.cpp @@ -0,0 +1,78 @@ +/* +********************************************************************** +* Copyright (c) 2004, International Business Machines +* Corporation and others. All Rights Reserved. +********************************************************************** +* Author: Alan Liu +* Created: April 20, 2004 +* Since: ICU 3.0 +********************************************************************** +*/ +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +#include "currfmt.h" +#include "unicode/numfmt.h" + +U_NAMESPACE_BEGIN + +CurrencyFormat::CurrencyFormat(const Locale& locale, UErrorCode& ec) : + fmt(NULL) { + fmt = NumberFormat::createCurrencyInstance(locale, ec); +} + +CurrencyFormat::CurrencyFormat(const CurrencyFormat& other) : + fmt(NULL) { + fmt = (NumberFormat*) other.fmt->clone(); +} + +CurrencyFormat::~CurrencyFormat() { + delete fmt; +} + +UBool CurrencyFormat::operator==(const Format& other) const { + if (this == &other) { + return TRUE; + } + if (other.getDynamicClassID() != CurrencyFormat::getStaticClassID()) { + return FALSE; + } + const CurrencyFormat* c = (const CurrencyFormat*) &other; + return *fmt == *c->fmt; +} + +Format* CurrencyFormat::clone() const { + return new CurrencyFormat(*this); +} + +UnicodeString& CurrencyFormat::format(const Formattable& obj, + UnicodeString& appendTo, + FieldPosition& pos, + UErrorCode& ec) const { + return fmt->format(obj, appendTo, pos, ec); +} + +UnicodeString& CurrencyFormat::format(const Formattable& obj, + UnicodeString& appendTo, + UErrorCode& ec) const { + return MeasureFormat::format(obj, appendTo, ec); +} + +void CurrencyFormat::parseObject(const UnicodeString& source, + Formattable& result, + ParsePosition& pos) const { + fmt->parseCurrency(source, result, pos); +} + +void CurrencyFormat::parseObject(const UnicodeString& source, + Formattable& result, + UErrorCode& ec) const { + MeasureFormat::parseObject(source, result, ec); +} + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CurrencyFormat) + +U_NAMESPACE_END + +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/icu4c/source/i18n/currfmt.h b/icu4c/source/i18n/currfmt.h new file mode 100644 index 00000000000..8af3d702b67 --- /dev/null +++ b/icu4c/source/i18n/currfmt.h @@ -0,0 +1,112 @@ +/* +********************************************************************** +* Copyright (c) 2004, International Business Machines +* Corporation and others. All Rights Reserved. +********************************************************************** +* Author: Alan Liu +* Created: April 20, 2004 +* Since: ICU 3.0 +********************************************************************** +*/ +#ifndef CURRENCYFORMAT_H +#define CURRENCYFORMAT_H + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +#include "unicode/measfmt.h" + +U_NAMESPACE_BEGIN + +class NumberFormat; + +/** + * Temporary internal concrete subclass of MeasureFormat implementing + * parsing and formatting of currency amount objects. This class is + * likely to be redesigned and rewritten in the near future. + * + *

This class currently delegates to DecimalFormat for parsing and + * formatting. + * + * @see MeasureFormat + * @author Alan Liu + * @internal + */ +class U_I18N_API CurrencyFormat : public MeasureFormat { + + public: + + /** + * Construct a CurrencyFormat for the given locale. + */ + CurrencyFormat(const Locale& locale, UErrorCode& ec); + + /** + * Copy constructor. + */ + CurrencyFormat(const CurrencyFormat& other); + + /** + * Destructor. + */ + virtual ~CurrencyFormat(); + + /** + * Override Format API. + */ + virtual UBool operator==(const Format& other) const; + + /** + * Override Format API. + */ + virtual Format* clone() const; + + /** + * Override Format API. + */ + virtual UnicodeString& format(const Formattable& obj, + UnicodeString& appendTo, + FieldPosition& pos, + UErrorCode& ec) const; + + /** + * Redeclare Format API to prevent hiding. + */ + UnicodeString& format(const Formattable& obj, + UnicodeString& appendTo, + UErrorCode& ec) const; + + /** + * Override Format API. + */ + virtual void parseObject(const UnicodeString& source, + Formattable& result, + ParsePosition& pos) const; + + /** + * Redeclare Format API to prevent hiding. + */ + void parseObject(const UnicodeString& source, + Formattable& result, + UErrorCode& ec) const; + + /** + * Override Format API. + */ + virtual UClassID getDynamicClassID() const; + + /** + * Returns the class ID for this class. + */ + static UClassID getStaticClassID(); + + private: + + NumberFormat* fmt; +}; + +U_NAMESPACE_END + +#endif // #if !UCONFIG_NO_FORMATTING +#endif // #ifndef CURRENCYFORMAT_H diff --git a/icu4c/source/i18n/decimfmt.cpp b/icu4c/source/i18n/decimfmt.cpp index c9a427c4b89..9bf281951e4 100644 --- a/icu4c/source/i18n/decimfmt.cpp +++ b/icu4c/source/i18n/decimfmt.cpp @@ -1198,12 +1198,6 @@ Formattable& DecimalFormat::parseCurrency(const UnicodeString& text, 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 diff --git a/icu4c/source/i18n/i18n.vcproj b/icu4c/source/i18n/i18n.vcproj index b4f8780523b..ba5780f9f9b 100644 --- a/icu4c/source/i18n/i18n.vcproj +++ b/icu4c/source/i18n/i18n.vcproj @@ -457,6 +457,12 @@ Outputs="..\..\include\unicode\$(InputFileName)"/> + + + + @@ -660,6 +666,26 @@ + + + + + + + + + + diff --git a/icu4c/source/i18n/measfmt.cpp b/icu4c/source/i18n/measfmt.cpp new file mode 100644 index 00000000000..4e95fc8778d --- /dev/null +++ b/icu4c/source/i18n/measfmt.cpp @@ -0,0 +1,42 @@ +/* +********************************************************************** +* Copyright (c) 2004, International Business Machines +* Corporation and others. All Rights Reserved. +********************************************************************** +* Author: Alan Liu +* Created: April 20, 2004 +* Since: ICU 3.0 +********************************************************************** +*/ +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +#include "unicode/measfmt.h" +#include "currfmt.h" + +U_NAMESPACE_BEGIN + +MeasureFormat* MeasureFormat::createCurrencyFormat(const Locale& locale, + UErrorCode& ec) { + CurrencyFormat* fmt = NULL; + if (U_SUCCESS(ec)) { + fmt = new CurrencyFormat(locale, ec); + if (U_FAILURE(ec)) { + delete fmt; + fmt = NULL; + } + } + return fmt; +} + +MeasureFormat* MeasureFormat::createCurrencyFormat(UErrorCode& ec) { + if (U_FAILURE(ec)) { + return NULL; + } + return MeasureFormat::createCurrencyFormat(Locale::getDefault(), ec); +} + +U_NAMESPACE_END + +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/icu4c/source/i18n/numfmt.cpp b/icu4c/source/i18n/numfmt.cpp index fe1a5523448..3a59f6306a0 100644 --- a/icu4c/source/i18n/numfmt.cpp +++ b/icu4c/source/i18n/numfmt.cpp @@ -1,6 +1,6 @@ /* ******************************************************************************* -* Copyright (C) 1997-2003, International Business Machines Corporation and * +* Copyright (C) 1997-2004, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* * @@ -348,19 +348,6 @@ Formattable& NumberFormat::parseCurrency(const UnicodeString& text, 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. diff --git a/icu4c/source/i18n/unicode/decimfmt.h b/icu4c/source/i18n/unicode/decimfmt.h index aaa38844284..d212a8418fd 100644 --- a/icu4c/source/i18n/unicode/decimfmt.h +++ b/icu4c/source/i18n/unicode/decimfmt.h @@ -885,35 +885,12 @@ public: * 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 + * @internal */ 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. diff --git a/icu4c/source/i18n/unicode/measfmt.h b/icu4c/source/i18n/unicode/measfmt.h new file mode 100644 index 00000000000..a253dd041c6 --- /dev/null +++ b/icu4c/source/i18n/unicode/measfmt.h @@ -0,0 +1,61 @@ +/* +********************************************************************** +* Copyright (c) 2004, International Business Machines +* Corporation and others. All Rights Reserved. +********************************************************************** +* Author: Alan Liu +* Created: April 20, 2004 +* Since: ICU 3.0 +********************************************************************** +*/ +#ifndef MEASUREFORMAT_H +#define MEASUREFORMAT_H + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +#include "unicode/format.h" + +U_NAMESPACE_BEGIN + +/** + * A formatter for measure objects. This is an abstract base class. + * + *

To format or parse a measure object, first create a formatter + * object using a MeasureFormat factory method. Then use that + * object's format and parse methods. + * + * @see Format + * @author Alan Liu + * @draft ICU 3.0 + */ +class U_I18N_API MeasureFormat : public Format { + + public: + + /** + * Return a formatter for CurrencyAmount objects in the given + * locale. + * @param locale desired locale + * @param ec input-output error code + * @return a formatter object, or NULL upon error + * @draft ICU 3.0 + */ + static MeasureFormat* createCurrencyFormat(const Locale& locale, + UErrorCode& ec); + + /** + * Return a formatter for CurrencyAmount objects in the default + * locale. + * @param ec input-output error code + * @return a formatter object, or NULL upon error + * @draft ICU 3.0 + */ + static MeasureFormat* createCurrencyFormat(UErrorCode& ec); +}; + +U_NAMESPACE_END + +#endif // #if !UCONFIG_NO_FORMATTING +#endif // #ifndef MEASUREFORMAT_H diff --git a/icu4c/source/i18n/unicode/numfmt.h b/icu4c/source/i18n/unicode/numfmt.h index decd564884a..70eee9d545f 100644 --- a/icu4c/source/i18n/unicode/numfmt.h +++ b/icu4c/source/i18n/unicode/numfmt.h @@ -387,34 +387,12 @@ public: * 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 + * @internal */ 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 diff --git a/icu4c/source/test/intltest/numfmtst.cpp b/icu4c/source/test/intltest/numfmtst.cpp index 8bdbb5b8c66..cc1e054806d 100644 --- a/icu4c/source/test/intltest/numfmtst.cpp +++ b/icu4c/source/test/intltest/numfmtst.cpp @@ -17,6 +17,7 @@ #include "unicode/decimfmt.h" #include "unicode/ucurr.h" #include "unicode/ustring.h" +#include "unicode/measfmt.h" #include "digitlst.h" #include "textfile.h" #include "tokiter.h" @@ -1583,7 +1584,9 @@ void NumberFormatTest::TestCases() { Locale loc("en", "US", ""); DecimalFormat *ref = 0, *fmt = 0; - UnicodeString pat, tok, str, out, where; + MeasureFormat *mfmt = 0; + UnicodeString pat, tok, mloc, str, out, where, currAmt; + Formattable n; for (;;) { ec = U_ZERO_ERROR; @@ -1609,7 +1612,6 @@ 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; @@ -1620,7 +1622,7 @@ void NumberFormatTest::TestCases() { ec = U_ZERO_ERROR; if (!tokens.next(tok, ec)) goto error; if (!tokens.next(tok, ec)) goto error; - if (cmd == 3 || cmd == 8) { + if (cmd == 3) { if (!tokens.next(tok, ec)) goto error; } continue; @@ -1633,7 +1635,6 @@ void NumberFormatTest::TestCases() { UnicodeString num; if (!tokens.next(num, ec)) goto error; if (!tokens.next(str, ec)) goto error; - Formattable n; ref->parse(num, n, ec); assertSuccess("parse", ec); assertEquals(where + "\"" + pat + "\".format(" + num + ")", @@ -1652,36 +1653,6 @@ void NumberFormatTest::TestCases() { n, m); } } - // fpc: - 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: else { UnicodeString expstr; @@ -1696,6 +1667,42 @@ void NumberFormatTest::TestCases() { exp, n); } break; + case 8: // fpc: + if (!tokens.next(tok, ec)) goto error; + if (tok != "-") { + mloc = tok; + delete mfmt; + mfmt = MeasureFormat::createCurrencyFormat( + Locale::createFromName(CharString(mloc)), ec); + if (U_FAILURE(ec)) { + errln("FAIL: " + where + "Loc \"" + mloc + "\": " + u_errorName(ec)); + ec = U_ZERO_ERROR; + if (!tokens.next(tok, ec)) goto error; + if (!tokens.next(tok, ec)) goto error; + if (!tokens.next(tok, ec)) goto error; + continue; + } + } + // fpc: + if (!tokens.next(currAmt, ec)) goto error; + if (!tokens.next(str, ec)) goto error; + parseCurrencyAmount(currAmt, *ref, (UChar)0x2F/*'/'*/, n, ec); + if (assertSuccess("parseCurrencyAmount", ec)) { + assertEquals(where + "getCurrencyFormat(" + mloc + ").format(" + currAmt + ")", + str, mfmt->format(n, out.remove(), ec)); + assertSuccess("format", ec); + } + if (!tokens.next(currAmt, ec)) goto error; + parseCurrencyAmount(currAmt, *ref, (UChar)0x2F/*'/'*/, n, ec); + if (assertSuccess("parseCurrencyAmount", ec)) { + Formattable m; + mfmt->parseObject(str, m, ec); + if (assertSuccess("parseCurrency", ec)) { + assertEquals(where + "getCurrencyFormat(" + mloc + ").parse(\"" + str + "\")", + n, m); + } + } + break; case 6: // perr: errln("FAIL: Under construction"); @@ -1759,6 +1766,7 @@ void NumberFormatTest::TestCases() { } done: + delete mfmt; delete fmt; delete ref; } diff --git a/icu4c/source/test/testdata/NumberFormatTestCases.txt b/icu4c/source/test/testdata/NumberFormatTestCases.txt index 1886c3e3769..5003e6dfc64 100644 --- a/icu4c/source/test/testdata/NumberFormatTestCases.txt +++ b/icu4c/source/test/testdata/NumberFormatTestCases.txt @@ -72,14 +72,14 @@ 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 +fpc: "en_US" 1234.56/USD "$1,234.56" 1234.56/USD +fpc: - 1234.56/JPY "\u00A51,235" 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 +fpc: - 123/QQQ "QQQ123.00" 123/QQQ # QQQ is fake +fpc: - 123/GTQ "Q123.00" 123/GTQ # ChoiceFormat-based display names -fpc: - 1/INR "Re. 1.00" 1/INR -fpc: - 2/INR "Rs. 2.00" 2/INR +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 +fpc: - 100/YDD "YDD100.00" 100/YDD +fpc: - 100/CNY "Y100.00" 100/CNY