ICU-6433 case sesitive parse for currency symbol and ISO code, case-insensitve for names, restrict parsing against only long names when pattern is plural pattern

X-SVN-Rev: 25537
This commit is contained in:
Xiaomei Ji 2009-03-10 06:12:24 +00:00
parent 37c509a085
commit 1472003a6c
3 changed files with 99 additions and 39 deletions

View file

@ -251,23 +251,28 @@ public class NumberFormatTest extends com.ibm.icu.dev.test.TestFmwk {
{"$\u00A0124 ", "5", "-1"},
{" $ 124 ", "0", "0"}, // TODO: need to handle space correctly
{"124$", "0", "3"}, // TODO: need to handle space correctly
{"124 $", "5", "-1"},
// {"124 $", "5", "-1"}, TODO: OK or NOT?
{"124 $", "0", "3"},
};
NumberFormat foo = NumberFormat.getCurrencyInstance();
for (int i = 0; i < DATA.length; ++i) {
ParsePosition parsePosition = new ParsePosition(0);
String stringToBeParsed = DATA[i][0];
int parsedPosition = Integer.parseInt(DATA[i][1]);
int errorIndex = Integer.parseInt(DATA[i][2]);
ParsePosition parsePosition = new ParsePosition(0);
String stringToBeParsed = DATA[i][0];
int parsedPosition = Integer.parseInt(DATA[i][1]);
int errorIndex = Integer.parseInt(DATA[i][2]);
try {
Number result = foo.parse(stringToBeParsed, parsePosition);
if (parsePosition.getIndex() != parsedPosition ||
parsePosition.getErrorIndex() != errorIndex) {
errln("FAILED parse " + stringToBeParsed);
errln("FAILED parse " + stringToBeParsed + "; parse position: " + parsePosition.getIndex() + "; error position: " + parsePosition.getErrorIndex());
}
if (parsePosition.getErrorIndex() == -1 &&
result.doubleValue() != 124) {
errln("FAILED parse " + stringToBeParsed);
errln("FAILED parse " + stringToBeParsed + "; value " + result.doubleValue());
}
} catch (Exception e) {
errln("FAILED " + e.toString());
}
}
}
@ -550,7 +555,7 @@ public class NumberFormatTest extends com.ibm.icu.dev.test.TestFmwk {
{"1.00 UAE dirha", "0", "4"},
{"1.00 us dollar", "14", "-1"},
{"1.00 US DOLLAR", "14", "-1"},
{"1.00 usd", "8", "-1"},
{"1.00 usd", "0", "4"},
};
ULocale locale = new ULocale("en_US");
for (int i=0; i<DATA.length; ++i) {
@ -562,8 +567,8 @@ public class NumberFormatTest extends com.ibm.icu.dev.test.TestFmwk {
Number val = numFmt.parse(stringToBeParsed, parsePosition);
if (parsePosition.getIndex() != parsedPosition ||
parsePosition.getErrorIndex() != errorIndex) {
errln("FAIL: parse failed. expected position: " + parsedPosition +"; actual: " + parsePosition.getIndex());
errln("FAIL: parse failed. expected error position: " + errorIndex + "; actual: " + parsePosition.getErrorIndex());
errln("FAIL: parse failed. expected position: " + parsedPosition +"; actual: " + parsePosition.getIndex());
}
if (parsePosition.getErrorIndex() == -1 &&
val.doubleValue() != 1.00) {

View file

@ -1932,7 +1932,7 @@ public class DecimalFormat extends NumberFormat {
} else {
if (!subparse(text, parsePosition, digitList, false, status,
currency, negPrefixPattern, negSuffixPattern,
posPrefixPattern, posSuffixPattern)) {
posPrefixPattern, posSuffixPattern, Currency.SYMBOL_NAME)) {
parsePosition.setIndex(backup);
return null;
}
@ -2031,9 +2031,16 @@ public class DecimalFormat extends NumberFormat {
boolean[] tmpStatus = new boolean[STATUS_LENGTH];
ParsePosition tmpPos = new ParsePosition(origPos);
DigitList tmpDigitList = new DigitList();
boolean found = subparse(text, tmpPos, tmpDigitList, false,
boolean found;
if (style == NumberFormat.PLURALCURRENCYSTYLE) {
found = subparse(text, tmpPos, tmpDigitList, false,
tmpStatus, currency, negPrefixPattern, negSuffixPattern,
posPrefixPattern, posSuffixPattern);
posPrefixPattern, posSuffixPattern, Currency.LONG_NAME);
} else {
found = subparse(text, tmpPos, tmpDigitList, false,
tmpStatus, currency, negPrefixPattern, negSuffixPattern,
posPrefixPattern, posSuffixPattern, Currency.SYMBOL_NAME);
}
if (found) {
if (tmpPos.getIndex() > maxPosIndex) {
maxPosIndex = tmpPos.getIndex();
@ -2056,7 +2063,7 @@ public class DecimalFormat extends NumberFormat {
boolean result = subparse(text, tmpPos, tmpDigitList, false,
tmpStatus, currency, affix.getNegPrefix(),
affix.getNegSuffix(), affix.getPosPrefix(),
affix.getPosSuffix());
affix.getPosSuffix(), affix.getPatternType());
if (result) {
found = true;
if (tmpPos.getIndex() > maxPosIndex) {
@ -2086,7 +2093,7 @@ public class DecimalFormat extends NumberFormat {
currencySignCount = 0;
boolean result = subparse(text, tmpPos, tmpDigitList, false,
tmpStatus, currency, negativePrefix, negativeSuffix,
positivePrefix, positiveSuffix);
positivePrefix, positiveSuffix, Currency.SYMBOL_NAME);
currencySignCount = savedCurrencySignCount;
if (result) {
if (tmpPos.getIndex() > maxPosIndex) {
@ -2135,7 +2142,8 @@ public class DecimalFormat extends NumberFormat {
AffixForCurrency affixes = new AffixForCurrency(negPrefixPattern,
negSuffixPattern,
posPrefixPattern,
posSuffixPattern);
posSuffixPattern,
Currency.SYMBOL_NAME);
affixPatternsForCurrency.add(affixes);
// add plural pattern
@ -2151,7 +2159,8 @@ public class DecimalFormat extends NumberFormat {
affixes = new AffixForCurrency(negPrefixPattern,
negSuffixPattern,
posPrefixPattern,
posSuffixPattern);
posSuffixPattern,
Currency.LONG_NAME);
affixPatternsForCurrency.add(affixes);
}
}
@ -2214,12 +2223,14 @@ public class DecimalFormat extends NumberFormat {
* @param negSuffix negative suffix pattern
* @param posPrefix positive prefix pattern
* @param negSuffix negative suffix pattern
* @param type type of currency to parse against, LONG_NAME only or not.
*/
private final boolean subparse(String text, ParsePosition parsePosition,
DigitList digits, boolean isExponent,
boolean status[], Currency currency[],
String negPrefix, String negSuffix,
String posPrefix, String posSuffix)
String posPrefix, String posSuffix,
int type)
{
int position = parsePosition.getIndex();
int oldStart = parsePosition.getIndex();
@ -2230,8 +2241,8 @@ public class DecimalFormat extends NumberFormat {
}
// Match positive and negative prefixes; prefer longest match.
int posMatch = compareAffix(text, position, false, true, posPrefix, currency);
int negMatch = compareAffix(text, position, true, true, negPrefix, currency);
int posMatch = compareAffix(text, position, false, true, posPrefix, type, currency);
int negMatch = compareAffix(text, position, true, true, negPrefix, type, currency);
if (posMatch >= 0 && negMatch >= 0) {
if (posMatch > negMatch) {
negMatch = -1;
@ -2556,10 +2567,10 @@ public class DecimalFormat extends NumberFormat {
// Match positive and negative suffixes; prefer longest match.
if (posMatch >= 0) {
posMatch = compareAffix(text, position, false, false, posSuffix, currency);
posMatch = compareAffix(text, position, false, false, posSuffix, type, currency);
}
if (negMatch >= 0) {
negMatch = compareAffix(text, position, true, false, negSuffix, currency);
negMatch = compareAffix(text, position, true, false, negSuffix, type, currency);
}
if (posMatch >= 0 && negMatch >= 0) {
if (posMatch > negMatch) {
@ -2632,6 +2643,7 @@ public class DecimalFormat extends NumberFormat {
* @param isNegative
* @param isPrefix
* @param affixPat affix pattern used for currency affix comparison
* @param type compare against currency type, LONG_NAME only or not.
* @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
@ -2641,10 +2653,11 @@ public class DecimalFormat extends NumberFormat {
private int compareAffix(String text, int pos,
boolean isNegative, boolean isPrefix,
String affixPat,
int type,
Currency[] currency) {
if (currency != null || currencyChoice != null ||
currencySignCount > 0) {
return compareComplexAffix(affixPat, text, pos, currency);
return compareComplexAffix(affixPat, text, pos, type, currency);
}
if (isPrefix) {
return compareSimpleAffix(isNegative ? negativePrefix : positivePrefix,
@ -2759,6 +2772,7 @@ public class DecimalFormat extends NumberFormat {
* @param affixPat pattern string
* @param text input text
* @param pos offset into input at which to begin matching
* @param type parse against currency type, LONG_NAME only or not.
* @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
@ -2766,7 +2780,7 @@ public class DecimalFormat extends NumberFormat {
* @return position after the matched text, or -1 if match failure
*/
private int compareComplexAffix(String affixPat, String text, int pos,
Currency[] currency) {
int type, Currency[] currency) {
int start = pos;
for (int i=0;
i < affixPat.length() && pos >= 0; ) {
@ -2831,7 +2845,7 @@ public class DecimalFormat extends NumberFormat {
// Delegate parse of display name => ISO code to Currency
ParsePosition ppos = new ParsePosition(pos);
// using Currency.parse to handle mixed style parsing.
String iso = Currency.parse(uloc, text, ppos);
String iso = Currency.parse(uloc, text, type, ppos);
// If parse succeeds, populate currency[0]
if (iso != null) {
@ -5752,14 +5766,20 @@ public class DecimalFormat extends NumberFormat {
private String posPrefixPatternForCurrency = null;
// positive suffix pattern
private String posSuffixPatternForCurrency = null;
private int patternType;
public AffixForCurrency() {}
public AffixForCurrency() {
patternType = Currency.SYMBOL_NAME;
}
public AffixForCurrency(String negPrefix, String negSuffix,
String posPrefix, String posSuffix) {
String posPrefix, String posSuffix,
int type) {
negPrefixPatternForCurrency = negPrefix;
negSuffixPatternForCurrency = negSuffix;
posPrefixPatternForCurrency = posPrefix;
posSuffixPatternForCurrency = posSuffix;
patternType = type;
}
public String getNegPrefix() {
@ -5777,6 +5797,10 @@ public class DecimalFormat extends NumberFormat {
public String getPosSuffix() {
return posSuffixPatternForCurrency;
}
public int getPatternType() {
return patternType;
}
}
// Affix patter set for currency.
// It is a set of AffixForCurrency,

View file

@ -720,6 +720,7 @@ public class Currency extends MeasureUnit implements Serializable {
*
* @param locale the locale of the display names to match
* @param text the text to parse
* @param type parse against currency type: LONG_NAME only or not
* @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
@ -730,20 +731,27 @@ public class Currency extends MeasureUnit implements Serializable {
* @internal
* @deprecated This API is ICU internal only.
*/
public static String parse(ULocale locale, String text, ParsePosition pos) {
TextTrieMap currencyNameTrie = (TextTrieMap)CURRENCY_NAME_CACHE.get(locale);
if (currencyNameTrie == null) {
currencyNameTrie = new TextTrieMap(true);
setupCurrencyNameTrie(locale, currencyNameTrie);
CURRENCY_NAME_CACHE.put(locale, currencyNameTrie);
public static String parse(ULocale locale, String text, int type, ParsePosition pos) {
//TextTrieMap currencyNameTrie = (TextTrieMap)CURRENCY_NAME_CACHE.get(locale);
Vector currencyTrieVec = (Vector)CURRENCY_NAME_CACHE.get(locale);
if (currencyTrieVec == null) {
TextTrieMap currencyNameTrie = new TextTrieMap(true);
TextTrieMap currencySymbolTrie = new TextTrieMap(false);
currencyTrieVec = new Vector();
currencyTrieVec.addElement(currencySymbolTrie);
currencyTrieVec.addElement(currencyNameTrie);
setupCurrencyTrieVec(locale, currencyTrieVec);
CURRENCY_NAME_CACHE.put(locale, currencyTrieVec);
}
// look for the names
int maxLength = 0;
String isoResult = null;
// look for the names
TextTrieMap currencyNameTrie = (TextTrieMap)currencyTrieVec.elementAt(1);
CurrencyNameResultHandler handler = new CurrencyNameResultHandler();
currencyNameTrie.find(text, pos.getIndex(), handler);
List list = handler.getMatchedCurrencyNames();
int maxLength = 0;
String isoResult = null;
if (list != null && list.size() != 0) {
Iterator it = list.iterator();
while (it.hasNext()) {
@ -757,12 +765,31 @@ public class Currency extends MeasureUnit implements Serializable {
}
}
if (type != Currency.LONG_NAME) { // not long name only
TextTrieMap currencySymbolTrie = (TextTrieMap)currencyTrieVec.elementAt(0);
handler = new CurrencyNameResultHandler();
currencySymbolTrie.find(text, pos.getIndex(), handler);
list = handler.getMatchedCurrencyNames();
if (list != null && list.size() != 0) {
Iterator it = list.iterator();
while (it.hasNext()) {
CurrencyStringInfo info = (CurrencyStringInfo)it.next();
String isoCode = info.getISOCode();
String currencyString = info.getCurrencyString();
if (currencyString.length() > maxLength) {
maxLength = currencyString.length();
isoResult = isoCode;
}
}
}
}
int start = pos.getIndex();
pos.setIndex(start + maxLength);
return isoResult;
}
private static void setupCurrencyNameTrie(ULocale locale, TextTrieMap trie) {
private static void setupCurrencyTrieVec(ULocale locale, Vector trieVec) {
// Look up the Currencies resource for the given locale. The
// Currencies locale data looks like this:
//|en {
@ -794,6 +821,10 @@ public class Currency extends MeasureUnit implements Serializable {
3. If there is no match, fall back to root and try again
4. If still no match, parse 3-letter ISO {this code is probably unchanged}.
*/
TextTrieMap symTrie = (TextTrieMap)trieVec.elementAt(0);
TextTrieMap trie = (TextTrieMap)trieVec.elementAt(1);
HashSet visited = new HashSet();
ULocale parentLocale = locale;
while (parentLocale != null) {
@ -807,7 +838,7 @@ public class Currency extends MeasureUnit implements Serializable {
String ISOCode = item.getKey();
if (!visited.contains(ISOCode)) {
CurrencyStringInfo info = new CurrencyStringInfo(ISOCode, ISOCode);
trie.put(ISOCode, info);
symTrie.put(ISOCode, info);
String name = item.getString(0);
if (name.length() > 1 && name.charAt(0) == '=' &&
@ -820,11 +851,11 @@ public class Currency extends MeasureUnit implements Serializable {
++nameIndex) {
info = new CurrencyStringInfo(ISOCode,
(String)names[nameIndex]);
trie.put((String)names[nameIndex], info);
symTrie.put((String)names[nameIndex], info);
}
} else {
info = new CurrencyStringInfo(ISOCode, name);
trie.put(name, info);
symTrie.put(name, info);
}
info = new CurrencyStringInfo(ISOCode, item.getString(1));