mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-14 17:24:01 +00:00
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:
parent
37c509a085
commit
1472003a6c
3 changed files with 99 additions and 39 deletions
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Add table
Reference in a new issue