ICU-2825 new architecture using Measures, Units, and MeasureFormat

X-SVN-Rev: 15011
This commit is contained in:
Alan Liu 2004-04-20 22:01:57 +00:00
parent 9a8ce89bc6
commit e2f4e501b6
10 changed files with 313 additions and 177 deletions

View file

@ -1006,7 +1006,7 @@ public class NumberFormatTest extends com.ibm.icu.dev.test.TestFmwk {
/*5*/ "p:", // <pattern or '-'> <string> <exp. number>
/*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>
/*8*/ "fpc:", // <loc or '-'> <curr.amt> <exp. string> <exp. curr.amt>
};
public void TestCases() {
@ -1016,7 +1016,8 @@ public class NumberFormatTest extends com.ibm.icu.dev.test.TestFmwk {
Locale loc = new Locale("en", "US", "");
DecimalFormat ref = null, fmt = null;
String pat = null;
MeasureFormat mfmt = null;
String pat = null, str = null, mloc = null;
try {
for (;;) {
@ -1040,7 +1041,6 @@ public class NumberFormatTest extends com.ibm.icu.dev.test.TestFmwk {
case 3: // fp:
case 4: // rt:
case 5: // p:
case 8: // fpc:
tok = tokens.next();
if (!tok.equals("-")) {
pat = tok;
@ -1051,11 +1051,11 @@ public class NumberFormatTest extends com.ibm.icu.dev.test.TestFmwk {
iae.printStackTrace();
tokens.next(); // consume remaining tokens
tokens.next();
if (cmd == 3 || cmd == 8) tokens.next();
if (cmd == 3) tokens.next();
continue;
}
}
String str = null;
str = null;
try {
if (cmd == 2 || cmd == 3 || cmd == 4) {
// f: <pattern or '-'> <number> <exp. string>
@ -1074,17 +1074,6 @@ public class NumberFormatTest extends com.ibm.icu.dev.test.TestFmwk {
n, fmt.parse(str));
}
}
// fpc: <pattern or '-'> <curr.amt> <exp. string> <exp. curr.amt>
else if (cmd == 8) {
String currAmt = tokens.next();
str = tokens.next();
CurrencyAmount n = parseCurrencyAmount(currAmt, ref, '/');
assertEquals(where + '"' + pat + "\".format(" + currAmt + ")",
str, fmt.format(n));
n = parseCurrencyAmount(tokens.next(), ref, '/');
assertEquals(where + '"' + pat + "\".parse(\"" + str + "\")",
n, fmt.parseCurrency(str));
}
// p: <pattern or '-'> <string to parse> <exp. number>
else {
str = tokens.next();
@ -1141,6 +1130,40 @@ public class NumberFormatTest extends com.ibm.icu.dev.test.TestFmwk {
}
}
break;
case 8: // fpc:
mloc = tokens.next();
if (!mloc.equals("-")) {
Locale l = LocaleUtility.getLocaleFromName(mloc);
try {
mfmt = MeasureFormat.getCurrencyFormat(new ULocale(l));
} catch (IllegalArgumentException iae) {
errln(where + "Loc \"" + tok + '"');
iae.printStackTrace();
tokens.next(); // consume remaining tokens
tokens.next();
tokens.next();
continue;
}
}
str = null;
try {
// fpc: <loc or '-'> <curr.amt> <exp. string> <exp. curr.amt>
if (cmd == 8) {
String currAmt = tokens.next();
str = tokens.next();
CurrencyAmount n = parseCurrencyAmount(currAmt, ref, '/');
assertEquals(where + mloc + ".format(" + currAmt + ")",
str, mfmt.format(n));
n = parseCurrencyAmount(tokens.next(), ref, '/');
assertEquals(where + mloc + ".parse(\"" + str + "\")",
n, (CurrencyAmount) mfmt.parseObject(str));
}
} catch (ParseException e) {
errln(where + '"' + pat + "\".parse(\"" + str +
"\") threw an exception");
e.printStackTrace();
}
break;
case -1:
errln("Unknown command \"" + tok + "\" at " + tokens.describePosition());
return;

View file

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

View file

@ -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
**********************************************************************
*/
package com.ibm.icu.text;
import java.text.FieldPosition;
import java.text.ParsePosition;
import com.ibm.icu.util.CurrencyAmount;
import com.ibm.icu.util.ULocale;
/**
* Temporary internal concrete subclass of MeasureFormat implementing
* parsing and formatting of CurrencyAmount objects. This class is
* likely to be redesigned and rewritten in the near future.
*
* <p>This class currently delegates to DecimalFormat for parsing and
* formatting.
*
* @see com.ibm.icu.text.UFormat
* @see com.ibm.icu.text.DecimalFormat
* @author Alan Liu
* @internal
*/
class CurrencyFormat extends MeasureFormat {
private NumberFormat fmt;
public CurrencyFormat(ULocale locale) {
fmt = NumberFormat.getCurrencyInstance(locale.toLocale());
}
/**
* Override Format.format().
* @see java.text.Format#format(java.lang.Object, java.lang.StringBuffer, java.text.FieldPosition)
*/
public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
try {
CurrencyAmount currency = (CurrencyAmount) obj;
fmt.setCurrency(currency.getCurrency());
return fmt.format(currency.getNumber(), toAppendTo, pos);
} catch (ClassCastException e) {
throw new IllegalArgumentException("Invalid type: " + obj.getClass().getName());
}
}
/**
* Override Format.parseObject().
* @see java.text.Format#parseObject(java.lang.String, java.text.ParsePosition)
*/
public Object parseObject(String source, ParsePosition pos) {
return fmt.parseCurrency(source, pos);
}
}

View file

@ -1317,10 +1317,13 @@ public class DecimalFormat extends NumberFormat {
/**
* <strong><font face=helvetica color=red>NEW</font></strong>
* Parses text from the given string as a CurrencyAmount. 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.
* Parses text from the given string as a CurrencyAmount. 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 pos input-output position; on input, the position within
@ -1328,9 +1331,9 @@ public class DecimalFormat extends NumberFormat {
* on output, the position after the last matched character. If
* the parse fails, the position in unchanged upon output.
* @return a CurrencyAmount, or null upon failure
* @draft ICU 3.0
* @internal
*/
public CurrencyAmount parseCurrency(String text, ParsePosition pos) {
CurrencyAmount parseCurrency(String text, ParsePosition pos) {
return (CurrencyAmount) parse(text, pos, true);
}
@ -1421,7 +1424,8 @@ public class DecimalFormat extends NumberFormat {
}
// Assemble into CurrencyAmount if necessary
return parseCurrency ? new CurrencyAmount(n, currency[0]) : n;
return parseCurrency ? (Object) new CurrencyAmount(n, currency[0])
: (Object) n;
}
private static final int STATUS_INFINITE = 0;

View file

@ -0,0 +1,48 @@
/*
**********************************************************************
* Copyright (c) 2004, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Author: Alan Liu
* Created: April 20, 2004
* Since: ICU 3.0
**********************************************************************
*/
package com.ibm.icu.text;
import com.ibm.icu.util.ULocale;
/**
* A formatter for Measure objects. This is an abstract base class.
*
* <p>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 com.ibm.icu.text.UFormat
* @author Alan Liu
* @draft ICU 3.0
*/
public abstract class MeasureFormat extends UFormat {
/**
* Return a formatter for CurrencyAmount objects in the given
* locale.
* @param locale desired locale
* @return a formatter object
* @draft ICU 3.0
*/
public static MeasureFormat getCurrencyFormat(ULocale locale) {
return new CurrencyFormat(locale);
}
/**
* Return a formatter for CurrencyAmount objects in the default
* locale.
* @return a formatter object
* @draft ICU 3.0
*/
public static MeasureFormat getCurrencyFormat() {
return getCurrencyFormat(ULocale.getDefault());
}
}

View file

@ -376,10 +376,13 @@ public abstract class NumberFormat extends UFormat {
/**
* <strong><font face=helvetica color=red>NEW</font></strong>
* Parses text from the given string as a CurrencyAmount. 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.
* Parses text from the given string as a CurrencyAmount. 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 pos input-output position; on input, the position within
@ -387,38 +390,14 @@ public abstract class NumberFormat extends UFormat {
* on output, the position after the last matched character. If
* the parse fails, the position in unchanged upon output.
* @return a CurrencyAmount, or null upon failure
* @draft ICU 3.0
* @internal
*/
public CurrencyAmount parseCurrency(String text, ParsePosition pos) {
CurrencyAmount parseCurrency(String text, ParsePosition pos) {
// Default implementation only -- subclasses should override
Number n = parse(text, pos);
return n == null ? null : new CurrencyAmount(n, getEffectiveCurrency());
}
/**
* <strong><font face=helvetica color=red>NEW</font></strong>
* Parses text from the beginning of the given string as a
* CurrencyAmount. The method might not use the entire text of
* the given string. 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
* @return a non-null CurrencyAmount
* @exception ParseException if the beginning of the specified string
* cannot be parsed.
* @draft ICU 3.0
*/
public CurrencyAmount parseCurrency(String text) throws ParseException {
ParsePosition pos = new ParsePosition(0);
CurrencyAmount result = parseCurrency(text, pos);
if (pos.getIndex() == 0) {
throw new ParseException("Unparseable currency: \"" + text + '"',
pos.getErrorIndex());
}
return result;
}
/**
* Returns true if this format will parse numbers as integers only.
* For example in the English locale, with ParseIntegerOnly true, the

View file

@ -36,7 +36,7 @@ import com.ibm.icu.impl.LocaleUtility;
* @author Alan Liu
* @stable ICU 2.2
*/
public class Currency implements Serializable {
public class Currency extends Unit implements Serializable {
/**
* ISO 4217 3-letter code.
@ -191,25 +191,17 @@ public class Currency implements Serializable {
* @stable ICU 2.2
*/
public boolean equals(Object rhs) {
if (rhs == null) return false;
if (rhs == this) return true;
try {
return equals((Currency)rhs);
Currency c = (Currency) rhs;
return isoCode.equals(c.isoCode);
}
catch (ClassCastException e) {
return false;
}
}
/**
* Return true if c is non-null and has the same currency code.
* @stable ICU 2.2
*/
public boolean equals(Currency c) {
if (c == null) return false;
if (c == this) return true;
return c.getClass() == Currency.class &&
this.isoCode.equals(c.isoCode);
}
/**
* Returns the ISO 4217 3-letter code for this currency object.
* @stable ICU 2.2

View file

@ -13,28 +13,16 @@ package com.ibm.icu.util;
import java.lang.Number;
/**
* An amount of currency, consisting of a Number and a Currency. This
* is a subclass of Number, and delegates all Number API to the
* enclosed Number object. CurrencyAmount objects are immutable.
*
* <p>NumberFormat formats and parses CurrencyAmount objects. During
* formatting, the currency of the object is used to determine the
* currency display name or symbol, the rounding, and the fraction
* digit counts. During parsing, if a valid currency is parsed, it is
* stored in the parsed CurrencyAmount object.
* An amount of currency, consisting of a Number and a Currency.
* CurrencyAmount objects are immutable.
*
* @see java.lang.Number
* @see Currency
* @see com.ibm.icu.text.NumberFormat
* @author Alan Liu
* @draft ICU 3.0
*/
public class CurrencyAmount extends Number {
public class CurrencyAmount extends Measure {
private Number number;
private Currency currency;
/**
* Constructs a new object given a number and a currency.
* @param number the number
@ -42,11 +30,7 @@ public class CurrencyAmount extends Number {
* @draft ICU 3.0
*/
public CurrencyAmount(Number number, Currency currency) {
if (number == null || currency == null) {
throw new NullPointerException();
}
this.number = number;
this.currency = currency;
super(number, currency);
}
/**
@ -56,96 +40,15 @@ public class CurrencyAmount extends Number {
* @draft ICU 3.0
*/
public CurrencyAmount(double number, Currency currency) {
this(new Double(number), currency);
super(new Double(number), currency);
}
/**
* Returns true if the given object is equal to this object.
* @return true if this object is equal to the given object
* @draft ICU 3.0
*/
public boolean equals(Object obj) {
if (obj == null) return false;
if (obj == this) return true;
try {
CurrencyAmount amt = (CurrencyAmount) obj;
return number.equals(amt.number) &&
currency.equals(amt.currency);
} catch (ClassCastException e) {
return false;
}
}
/**
* Returns a hashcode for this object.
* @return a 32-bit hash
* @draft ICU 3.0
*/
public int hashCode() {
return number.hashCode() ^ currency.hashCode();
}
/**
* Returns a string representation of this object.
* @return a string representation consisting of the ISO currency
* code together with the numeric amount
* @draft ICU 3.0
*/
public String toString() {
return currency.getCurrencyCode() + ' ' + number;
}
/**
* Returns the numeric value of this object.
* @return this object's Number
* @draft ICU 3.0
*/
public Number getNumber() {
return number;
}
/**
* Returns the currency of this object.
* @return this object's Currency
* @draft ICU 3.0
*/
public Currency getCurrency() {
return currency;
}
/**
* Returns the value of this current amount as an int.
* @return getNumber().intValue()
* @draft ICU 3.0
*/
public int intValue() {
return number.intValue();
}
/**
* Returns the value of this current amount as an long.
* @return getNumber().longValue()
* @draft ICU 3.0
*/
public long longValue() {
return number.longValue();
}
/**
* Returns the value of this current amount as an float.
* @return getNumber().floatValue()
* @draft ICU 3.0
*/
public float floatValue() {
return number.floatValue();
}
/**
* Returns the value of this current amount as an double.
* @return getNumber().doubleValue()
* @draft ICU 3.0
*/
public double doubleValue() {
return number.doubleValue();
return (Currency) getUnit();
}
}

View file

@ -0,0 +1,104 @@
/*
**********************************************************************
* Copyright (c) 2004, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Author: Alan Liu
* Created: April 20, 2004
* Since: ICU 3.0
**********************************************************************
*/
package com.ibm.icu.util;
import java.lang.Number;
/**
* An amount of a specified unit, consisting of a Number and a Unit.
* For example, a length measure consists of a Number and a length
* unit, such as feet or meters. This is an abstract class.
* Subclasses specify a concrete Unit type.
*
* <p>Measure objects are parsed and formatted by subclasses of
* MeasureFormat.
*
* <p>Measure objects are immutable.
*
* @see java.lang.Number
* @see com.ibm.icu.util.Unit
* @see com.ibm.icu.text.MeasureFormat
* @author Alan Liu
* @draft ICU 3.0
*/
public abstract class Measure {
private Number number;
private Unit unit;
/**
* Constructs a new object given a number and a unit.
* @param number the number
* @param currency the currency
* @draft ICU 3.0
*/
protected Measure(Number number, Unit unit) {
if (number == null || unit == null) {
throw new NullPointerException();
}
this.number = number;
this.unit = unit;
}
/**
* Returns true if the given object is equal to this object.
* @return true if this object is equal to the given object
* @draft ICU 3.0
*/
public boolean equals(Object obj) {
if (obj == null) return false;
if (obj == this) return true;
try {
Measure m = (Measure) obj;
return number.equals(m.number) && unit.equals(m.unit);
} catch (ClassCastException e) {
return false;
}
}
/**
* Returns a hashcode for this object.
* @return a 32-bit hash
* @draft ICU 3.0
*/
public int hashCode() {
return number.hashCode() ^ unit.hashCode();
}
/**
* Returns a string representation of this object.
* @return a string representation consisting of the ISO currency
* code together with the numeric amount
* @draft ICU 3.0
*/
public String toString() {
return number.toString() + ' ' + unit.toString();
}
/**
* Returns the numeric value of this object.
* @return this object's Number
* @draft ICU 3.0
*/
public Number getNumber() {
return number;
}
/**
* Returns the unit of this object.
* @return this object's Unit
* @draft ICU 3.0
*/
public Unit getUnit() {
return unit;
}
}

View file

@ -0,0 +1,22 @@
/*
**********************************************************************
* Copyright (c) 2004, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Author: Alan Liu
* Created: April 20, 2004
* Since: ICU 3.0
**********************************************************************
*/
package com.ibm.icu.util;
/**
* A unit such as length, mass, volume, currency, etc. A unit is
* coupled with a numeric amount to produce a Measure.
*
* @see com.ibm.icu.util.Measure
* @author Alan Liu
* @draft ICU 3.0
*/
public abstract class Unit {
}