ICU-6433 currency parsing, case sensitive against symbol and ISO, case insensitive against name; parse against plural pattern using names only
X-SVN-Rev: 25540
This commit is contained in:
parent
2dfb80a9e1
commit
1f2dcc4fb2
@ -106,7 +106,8 @@ U_CALLCONV AffixPatternValueComparator(UHashTok val1, UHashTok val2) {
|
||||
affix_1->posPrefixPatternForCurrency ==
|
||||
affix_2->posPrefixPatternForCurrency &&
|
||||
affix_1->posSuffixPatternForCurrency ==
|
||||
affix_2->posSuffixPatternForCurrency;
|
||||
affix_2->posSuffixPatternForCurrency &&
|
||||
affix_1->patternType == affix_2->patternType;
|
||||
}
|
||||
|
||||
|
||||
@ -534,7 +535,8 @@ DecimalFormat::setupCurrencyAffixPatterns(UErrorCode& status) {
|
||||
*fNegPrefixPattern,
|
||||
*fNegSuffixPattern,
|
||||
*fPosPrefixPattern,
|
||||
*fPosSuffixPattern);
|
||||
*fPosSuffixPattern,
|
||||
UCURR_SYMBOL_NAME);
|
||||
fAffixPatternsForCurrency->put("default", affixPtn, status);
|
||||
}
|
||||
|
||||
@ -555,7 +557,8 @@ DecimalFormat::setupCurrencyAffixPatterns(UErrorCode& status) {
|
||||
*fNegPrefixPattern,
|
||||
*fNegSuffixPattern,
|
||||
*fPosPrefixPattern,
|
||||
*fPosSuffixPattern);
|
||||
*fPosSuffixPattern,
|
||||
UCURR_LONG_NAME);
|
||||
fAffixPatternsForCurrency->put(*key, affixPtn, status);
|
||||
}
|
||||
}
|
||||
@ -1626,7 +1629,7 @@ void DecimalFormat::parse(const UnicodeString& text,
|
||||
if (!subparse(text,
|
||||
fNegPrefixPattern, fNegSuffixPattern,
|
||||
fPosPrefixPattern, fPosSuffixPattern,
|
||||
FALSE,
|
||||
FALSE, UCURR_SYMBOL_NAME,
|
||||
parsePosition, digits, status, currency)) {
|
||||
parsePosition.setIndex(backup);
|
||||
return;
|
||||
@ -1706,11 +1709,20 @@ DecimalFormat::parseForCurrency(const UnicodeString& text,
|
||||
UBool tmpStatus[fgStatusLength];
|
||||
ParsePosition tmpPos(origPos);
|
||||
DigitList tmpDigitList;
|
||||
UBool found = subparse(text,
|
||||
fNegPrefixPattern, fNegSuffixPattern,
|
||||
fPosPrefixPattern, fPosSuffixPattern,
|
||||
TRUE,
|
||||
tmpPos, tmpDigitList, tmpStatus, currency);
|
||||
UBool found;
|
||||
if (fStyle == NumberFormat::kPluralCurrencyStyle) {
|
||||
found = subparse(text,
|
||||
fNegPrefixPattern, fNegSuffixPattern,
|
||||
fPosPrefixPattern, fPosSuffixPattern,
|
||||
TRUE, UCURR_LONG_NAME,
|
||||
tmpPos, tmpDigitList, tmpStatus, currency);
|
||||
} else {
|
||||
found = subparse(text,
|
||||
fNegPrefixPattern, fNegSuffixPattern,
|
||||
fPosPrefixPattern, fPosSuffixPattern,
|
||||
TRUE, UCURR_SYMBOL_NAME,
|
||||
tmpPos, tmpDigitList, tmpStatus, currency);
|
||||
}
|
||||
if (found) {
|
||||
if (tmpPos.getIndex() > maxPosIndex) {
|
||||
maxPosIndex = tmpPos.getIndex();
|
||||
@ -1738,7 +1750,7 @@ DecimalFormat::parseForCurrency(const UnicodeString& text,
|
||||
&affixPtn->negSuffixPatternForCurrency,
|
||||
&affixPtn->posPrefixPatternForCurrency,
|
||||
&affixPtn->posSuffixPatternForCurrency,
|
||||
TRUE,
|
||||
TRUE, affixPtn->patternType,
|
||||
tmpPos, tmpDigitList, tmpStatus, currency);
|
||||
if (result) {
|
||||
found = true;
|
||||
@ -1771,7 +1783,7 @@ DecimalFormat::parseForCurrency(const UnicodeString& text,
|
||||
UBool result = subparse(text,
|
||||
&fNegativePrefix, &fNegativeSuffix,
|
||||
&fPositivePrefix, &fPositiveSuffix,
|
||||
FALSE,
|
||||
FALSE, UCURR_SYMBOL_NAME,
|
||||
tmpPos_2, tmpDigitList_2, tmpStatus_2,
|
||||
currency);
|
||||
if (result) {
|
||||
@ -1816,6 +1828,7 @@ is here if we change our minds.
|
||||
* @param posPrefix positive prefix.
|
||||
* @param posSuffix positive suffix.
|
||||
* @param currencyParsing whether it is currency parsing or not.
|
||||
* @param type the currency type to parse against, LONG_NAME only or not.
|
||||
* @param parsePosition The position at which to being parsing. Upon
|
||||
* return, the first unparsed character.
|
||||
* @param digits the DigitList to set to the parsed value.
|
||||
@ -1832,6 +1845,7 @@ UBool DecimalFormat::subparse(const UnicodeString& text,
|
||||
const UnicodeString* posPrefix,
|
||||
const UnicodeString* posSuffix,
|
||||
UBool currencyParsing,
|
||||
int8_t type,
|
||||
ParsePosition& parsePosition,
|
||||
DigitList& digits, UBool* status,
|
||||
UChar* currency) const
|
||||
@ -1845,8 +1859,8 @@ UBool DecimalFormat::subparse(const UnicodeString& text,
|
||||
}
|
||||
|
||||
// Match positive and negative prefixes; prefer longest match.
|
||||
int32_t posMatch = compareAffix(text, position, FALSE, TRUE, posPrefix, currencyParsing, currency);
|
||||
int32_t negMatch = compareAffix(text, position, TRUE, TRUE, negPrefix,currencyParsing, currency);
|
||||
int32_t posMatch = compareAffix(text, position, FALSE, TRUE, posPrefix, currencyParsing, type, currency);
|
||||
int32_t negMatch = compareAffix(text, position, TRUE, TRUE, negPrefix,currencyParsing, type, currency);
|
||||
if (posMatch >= 0 && negMatch >= 0) {
|
||||
if (posMatch > negMatch) {
|
||||
negMatch = -1;
|
||||
@ -2061,10 +2075,10 @@ UBool DecimalFormat::subparse(const UnicodeString& text,
|
||||
|
||||
// Match positive and negative suffixes; prefer longest match.
|
||||
if (posMatch >= 0) {
|
||||
posMatch = compareAffix(text, position, FALSE, FALSE, posSuffix, currencyParsing, currency);
|
||||
posMatch = compareAffix(text, position, FALSE, FALSE, posSuffix, currencyParsing, type, currency);
|
||||
}
|
||||
if (negMatch >= 0) {
|
||||
negMatch = compareAffix(text, position, TRUE, FALSE, negSuffix, currencyParsing, currency);
|
||||
negMatch = compareAffix(text, position, TRUE, FALSE, negSuffix, currencyParsing, type, currency);
|
||||
}
|
||||
if (posMatch >= 0 && negMatch >= 0) {
|
||||
if (posMatch > negMatch) {
|
||||
@ -2124,6 +2138,7 @@ int32_t DecimalFormat::skipPadding(const UnicodeString& text, int32_t position)
|
||||
* @param isPrefix
|
||||
* @param affixPat affix pattern used for currency affix comparison.
|
||||
* @param currencyParsing whether it is currency parsing or not
|
||||
* @param type the currency type to parse against, 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
|
||||
@ -2136,6 +2151,7 @@ int32_t DecimalFormat::compareAffix(const UnicodeString& text,
|
||||
UBool isPrefix,
|
||||
const UnicodeString* affixPat,
|
||||
UBool currencyParsing,
|
||||
int8_t type,
|
||||
UChar* currency) const
|
||||
{
|
||||
const UnicodeString *patternToCompare;
|
||||
@ -2143,7 +2159,7 @@ int32_t DecimalFormat::compareAffix(const UnicodeString& text,
|
||||
(fCurrencySignCount > fgCurrencySignCountZero && currencyParsing)) {
|
||||
|
||||
if (affixPat != NULL) {
|
||||
return compareComplexAffix(*affixPat, text, pos, currency);
|
||||
return compareComplexAffix(*affixPat, text, pos, type, currency);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2270,6 +2286,7 @@ 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 type the currency type to parse against, 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
|
||||
@ -2279,6 +2296,7 @@ int32_t DecimalFormat::skipUWhiteSpace(const UnicodeString& text, int32_t pos) {
|
||||
int32_t DecimalFormat::compareComplexAffix(const UnicodeString& affixPat,
|
||||
const UnicodeString& text,
|
||||
int32_t pos,
|
||||
int8_t type,
|
||||
UChar* currency) const
|
||||
{
|
||||
int32_t start = pos;
|
||||
@ -2325,7 +2343,7 @@ int32_t DecimalFormat::compareComplexAffix(const UnicodeString& affixPat,
|
||||
UChar curr[4];
|
||||
UErrorCode ec = U_ZERO_ERROR;
|
||||
// Delegate parse of display name => ISO code to Currency
|
||||
uprv_parseCurrency(loc, text, ppos, curr, ec);
|
||||
uprv_parseCurrency(loc, text, ppos, type, curr, ec);
|
||||
|
||||
// If parse succeeds, populate currency[0]
|
||||
if (U_SUCCESS(ec) && ppos.getIndex() != pos) {
|
||||
@ -4509,7 +4527,8 @@ DecimalFormat::copyHashForAffixPattern(const Hashtable* source,
|
||||
value->negPrefixPatternForCurrency,
|
||||
value->negSuffixPatternForCurrency,
|
||||
value->posPrefixPatternForCurrency,
|
||||
value->posSuffixPatternForCurrency);
|
||||
value->posSuffixPatternForCurrency,
|
||||
value->patternType);
|
||||
target->put(UnicodeString(*key), copy, status);
|
||||
if ( U_FAILURE(status) ) {
|
||||
return;
|
||||
|
@ -634,6 +634,9 @@ ucurr_getPluralName(const UChar* currency,
|
||||
|
||||
#define NEED_TO_BE_DELETED 0x1
|
||||
|
||||
// TODO: a better way to define this?
|
||||
#define MAX_CURRENCY_NAME_LEN 100
|
||||
|
||||
typedef struct {
|
||||
const char* IsoCode; // key
|
||||
UChar* currencyName; // value
|
||||
@ -646,6 +649,11 @@ typedef struct {
|
||||
#define MIN(a,b) (((a)<(b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a,b) (((a)<(b)) ? (b) : (a))
|
||||
#endif
|
||||
|
||||
|
||||
// Comparason function used in quick sort.
|
||||
static int currencyNameComparator(const void* a, const void* b) {
|
||||
const CurrencyNameStruct* currName_1 = (const CurrencyNameStruct*)a;
|
||||
@ -677,9 +685,10 @@ static int currencyNameComparator(const void* a, const void* b) {
|
||||
// For example, given locale as "en_US", the currency names get from resource
|
||||
// bundle in "en_US" and "en" are duplicated. The fallback mechanism will count
|
||||
// all currency names in "en_US" and "en".
|
||||
static int32_t
|
||||
getCurrencyNameCount(const char* loc) {
|
||||
int32_t total_currency_count = 0;
|
||||
static void
|
||||
getCurrencyNameCount(const char* loc, int* total_currency_name_count, int* total_currency_symbol_count) {
|
||||
*total_currency_name_count = 0;
|
||||
*total_currency_symbol_count = 0;
|
||||
const UChar* s = NULL;
|
||||
char locale[ULOC_FULLNAME_CAPACITY];
|
||||
uprv_strcpy(locale, loc);
|
||||
@ -705,12 +714,13 @@ getCurrencyNameCount(const char* loc) {
|
||||
ChoiceFormat fmt(s, ec2);
|
||||
int32_t fmt_count;
|
||||
fmt.getFormats(fmt_count);
|
||||
total_currency_count += fmt_count;
|
||||
*total_currency_symbol_count += fmt_count;
|
||||
} else {
|
||||
++total_currency_count; // currency symbol
|
||||
++(*total_currency_symbol_count); // currency symbol
|
||||
}
|
||||
|
||||
total_currency_count += 2; // long name and iso code
|
||||
++(*total_currency_symbol_count); // iso code
|
||||
++(*total_currency_name_count); // long name
|
||||
ures_close(names);
|
||||
}
|
||||
|
||||
@ -720,7 +730,7 @@ getCurrencyNameCount(const char* loc) {
|
||||
n = ures_getSize(curr_p);
|
||||
for (int32_t i=0; i<n; ++i) {
|
||||
UResourceBundle* names = ures_getByIndex(curr_p, i, NULL, &ec3);
|
||||
total_currency_count += ures_getSize(names);
|
||||
*total_currency_name_count += ures_getSize(names);
|
||||
ures_close(names);
|
||||
}
|
||||
ures_close(curr_p);
|
||||
@ -731,7 +741,22 @@ getCurrencyNameCount(const char* loc) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return total_currency_count;
|
||||
}
|
||||
|
||||
// TODO: locale dependent
|
||||
static UChar*
|
||||
toUpperCase(const UChar* source, int32_t len) {
|
||||
UChar* dest = NULL;
|
||||
UErrorCode ec = U_ZERO_ERROR;
|
||||
int32_t destLen = u_strToUpper(dest, 0, source, len, NULL, &ec);
|
||||
|
||||
ec = U_ZERO_ERROR;
|
||||
dest = (UChar*)uprv_malloc(sizeof(UChar) * MAX(destLen, len));
|
||||
u_strToUpper(dest, destLen, source, len, NULL, &ec);
|
||||
if (U_FAILURE(ec)) {
|
||||
uprv_memcpy(dest, source, sizeof(UChar) * len);
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
||||
@ -741,8 +766,12 @@ getCurrencyNameCount(const char* loc) {
|
||||
// "CurrencyPlural", enable fallback chain.
|
||||
// return the malloc-ed currency name arrays and the total number of currency
|
||||
// names in the array.
|
||||
static CurrencyNameStruct*
|
||||
collectCurrencyNames(const char* locale, int32_t* total_currency_count,
|
||||
static void
|
||||
collectCurrencyNames(const char* locale,
|
||||
CurrencyNameStruct** currencyNames,
|
||||
int32_t* total_currency_name_count,
|
||||
CurrencyNameStruct** currencySymbols,
|
||||
int32_t* total_currency_symbol_count,
|
||||
UErrorCode& ec) {
|
||||
// Look up the Currencies resource for the given locale.
|
||||
UErrorCode ec2 = U_ZERO_ERROR;
|
||||
@ -751,19 +780,21 @@ collectCurrencyNames(const char* locale, int32_t* total_currency_count,
|
||||
uloc_getName(locale, loc, sizeof(loc), &ec2);
|
||||
if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) {
|
||||
ec = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Get maximum currency name count first.
|
||||
int32_t max_currency_count = getCurrencyNameCount(loc);
|
||||
getCurrencyNameCount(loc, total_currency_name_count, total_currency_symbol_count);
|
||||
|
||||
CurrencyNameStruct* currencyNames = (CurrencyNameStruct*)uprv_malloc
|
||||
(sizeof(CurrencyNameStruct) * (max_currency_count));
|
||||
*currencyNames = (CurrencyNameStruct*)uprv_malloc
|
||||
(sizeof(CurrencyNameStruct) * (*total_currency_name_count));
|
||||
*currencySymbols = (CurrencyNameStruct*)uprv_malloc
|
||||
(sizeof(CurrencyNameStruct) * (*total_currency_symbol_count));
|
||||
|
||||
const UChar* s = NULL; // currency name
|
||||
char* iso = NULL; // currency ISO code
|
||||
|
||||
*total_currency_count = 0;
|
||||
*total_currency_name_count = 0;
|
||||
*total_currency_symbol_count = 0;
|
||||
|
||||
UErrorCode ec3 = U_ZERO_ERROR;
|
||||
UErrorCode ec4 = U_ZERO_ERROR;
|
||||
@ -810,35 +841,36 @@ collectCurrencyNames(const char* locale, int32_t* total_currency_count,
|
||||
int32_t length = formats[i].length();
|
||||
UChar* name = (UChar*)uprv_malloc(sizeof(UChar)*length);
|
||||
formats[i].extract(0, length, name);
|
||||
currencyNames[*total_currency_count].IsoCode = iso;
|
||||
currencyNames[*total_currency_count].currencyName = name;
|
||||
currencyNames[*total_currency_count].flag = NEED_TO_BE_DELETED;
|
||||
currencyNames[(*total_currency_count)++].currencyNameLen = length;
|
||||
(*currencySymbols)[*total_currency_symbol_count].IsoCode = iso;
|
||||
(*currencySymbols)[*total_currency_symbol_count].currencyName = name;
|
||||
(*currencySymbols)[*total_currency_symbol_count].flag = NEED_TO_BE_DELETED;
|
||||
(*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = length;
|
||||
}
|
||||
} else {
|
||||
// Add currency symbol.
|
||||
currencyNames[*total_currency_count].IsoCode = iso;
|
||||
currencyNames[*total_currency_count].currencyName = (UChar*)s;
|
||||
currencyNames[*total_currency_count].flag = 0;
|
||||
currencyNames[(*total_currency_count)++].currencyNameLen = len;
|
||||
(*currencySymbols)[*total_currency_symbol_count].IsoCode = iso;
|
||||
(*currencySymbols)[*total_currency_symbol_count].currencyName = (UChar*)s;
|
||||
(*currencySymbols)[*total_currency_symbol_count].flag = 0;
|
||||
(*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = len;
|
||||
}
|
||||
|
||||
// Add currency long name.
|
||||
s = ures_getStringByIndex(names, UCURR_LONG_NAME, &len, &ec2);
|
||||
currencyNames[*total_currency_count].IsoCode = iso;
|
||||
currencyNames[*total_currency_count].currencyName = (UChar*)s;
|
||||
currencyNames[*total_currency_count].flag = 0;
|
||||
currencyNames[(*total_currency_count)++].currencyNameLen = len;
|
||||
(*currencyNames)[*total_currency_name_count].IsoCode = iso;
|
||||
UChar* upperName = toUpperCase(s, len);
|
||||
(*currencyNames)[*total_currency_name_count].currencyName = upperName;
|
||||
(*currencyNames)[*total_currency_name_count].flag = NEED_TO_BE_DELETED;
|
||||
(*currencyNames)[(*total_currency_name_count)++].currencyNameLen = len;
|
||||
|
||||
// put (iso, 3, and iso) in to array
|
||||
// Add currency ISO code.
|
||||
currencyNames[*total_currency_count].IsoCode = iso;
|
||||
currencyNames[*total_currency_count].currencyName = (UChar*)uprv_malloc(sizeof(UChar)*3);
|
||||
currencyNames[*total_currency_count].currencyName[0] = iso[0];
|
||||
currencyNames[*total_currency_count].currencyName[1] = iso[1];
|
||||
currencyNames[*total_currency_count].currencyName[2] = iso[2];
|
||||
currencyNames[*total_currency_count].flag = NEED_TO_BE_DELETED;
|
||||
currencyNames[(*total_currency_count)++].currencyNameLen = 3;
|
||||
(*currencySymbols)[*total_currency_symbol_count].IsoCode = iso;
|
||||
(*currencySymbols)[*total_currency_symbol_count].currencyName = (UChar*)uprv_malloc(sizeof(UChar)*3);
|
||||
(*currencySymbols)[*total_currency_symbol_count].currencyName[0] = iso[0];
|
||||
(*currencySymbols)[*total_currency_symbol_count].currencyName[1] = iso[1];
|
||||
(*currencySymbols)[*total_currency_symbol_count].currencyName[2] = iso[2];
|
||||
(*currencySymbols)[*total_currency_symbol_count].flag = NEED_TO_BE_DELETED;
|
||||
(*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = 3;
|
||||
|
||||
ures_close(names);
|
||||
}
|
||||
@ -867,10 +899,11 @@ collectCurrencyNames(const char* locale, int32_t* total_currency_count,
|
||||
// TODO: remove duplicates between singular name and
|
||||
// currency long name?
|
||||
s = ures_getStringByIndex(names, j, &len, &ec3);
|
||||
currencyNames[*total_currency_count].IsoCode = iso;
|
||||
currencyNames[*total_currency_count].currencyName = (UChar*)s;
|
||||
currencyNames[*total_currency_count].flag = 0;
|
||||
currencyNames[(*total_currency_count)++].currencyNameLen = len;
|
||||
(*currencyNames)[*total_currency_name_count].IsoCode = iso;
|
||||
UChar* upperName = toUpperCase(s, len);
|
||||
(*currencyNames)[*total_currency_name_count].currencyName = upperName;
|
||||
(*currencyNames)[*total_currency_name_count].flag = NEED_TO_BE_DELETED;
|
||||
(*currencyNames)[(*total_currency_name_count)++].currencyNameLen = len;
|
||||
}
|
||||
ures_close(names);
|
||||
}
|
||||
@ -887,42 +920,51 @@ collectCurrencyNames(const char* locale, int32_t* total_currency_count,
|
||||
uhash_close(currencyPluralIsoCodes);
|
||||
|
||||
// quick sort the struct
|
||||
qsort(currencyNames, *total_currency_count, sizeof(CurrencyNameStruct),
|
||||
currencyNameComparator);
|
||||
qsort(*currencyNames, *total_currency_name_count,
|
||||
sizeof(CurrencyNameStruct), currencyNameComparator);
|
||||
qsort(*currencySymbols, *total_currency_symbol_count,
|
||||
sizeof(CurrencyNameStruct), currencyNameComparator);
|
||||
|
||||
#ifdef UCURR_DEBUG
|
||||
for (int32_t index = 0; index < *total_currency_count; ++index) {
|
||||
printf("currency name count: %d\n", *total_currency_name_count);
|
||||
for (int32_t index = 0; index < *total_currency_name_count; ++index) {
|
||||
printf("index: %d\n", index);
|
||||
printf("iso: %s\n", currencyNames[index].IsoCode);
|
||||
printf("iso: %s\n", (*currencyNames)[index].IsoCode);
|
||||
printf("currencyName:");
|
||||
for (int32_t i = 0; i < currencyNames[index].currencyNameLen; ++i) {
|
||||
printf("%c", (unsigned char)currencyNames[index].currencyName[i]);
|
||||
for (int32_t i = 0; i < (*currencyNames)[index].currencyNameLen; ++i) {
|
||||
printf("%c", (unsigned char)(*currencyNames)[index].currencyName[i]);
|
||||
}
|
||||
printf("\n");
|
||||
printf("len: %d\n", currencyNames[index].currencyNameLen);
|
||||
printf("len: %d\n", (*currencyNames)[index].currencyNameLen);
|
||||
}
|
||||
printf("currency symbol count: %d\n", *total_currency_symbol_count);
|
||||
for (int32_t index = 0; index < *total_currency_symbol_count; ++index) {
|
||||
printf("index: %d\n", index);
|
||||
printf("iso: %s\n", (*currencySymbols)[index].IsoCode);
|
||||
printf("currencySymbol:");
|
||||
for (int32_t i = 0; i < (*currencySymbols)[index].currencyNameLen; ++i) {
|
||||
printf("%c", (unsigned char)(*currencySymbols)[index].currencyName[i]);
|
||||
}
|
||||
printf("\n");
|
||||
printf("len: %d\n", (*currencySymbols)[index].currencyNameLen);
|
||||
}
|
||||
printf("currency count: %d\n", *total_currency_count);
|
||||
#endif
|
||||
|
||||
return currencyNames;
|
||||
}
|
||||
|
||||
// @param currencyNames: currency names array
|
||||
// @param indexInCurrencyNames: the index of the character in currency names
|
||||
// array against which the comparison is done
|
||||
// @param text: input text to compare against
|
||||
// @param pos: the position of character in input text to compare against
|
||||
// @param key: input text char to compare against
|
||||
// @param begin(IN/OUT): the begin index of matching range in currency names array
|
||||
// @param end(IN/OUT): the end index of matching range in currency names array.
|
||||
static int32_t
|
||||
binarySearch(const CurrencyNameStruct* currencyNames,
|
||||
int32_t indexInCurrencyNames,
|
||||
const UnicodeString* text, int32_t pos,
|
||||
const UChar key,
|
||||
int32_t* begin, int32_t* end) {
|
||||
#ifdef UCURR_DEBUG
|
||||
printf("pos = %d\n", pos);
|
||||
printf("key = %x\n", key);
|
||||
#endif
|
||||
UChar key = text->charAt(pos);
|
||||
int32_t first = *begin;
|
||||
int32_t last = *end;
|
||||
while (first <= last) {
|
||||
@ -1024,7 +1066,7 @@ binarySearch(const CurrencyNameStruct* currencyNames,
|
||||
// Linear search "text" in "currencyNames".
|
||||
// @param begin, end: the begin and end index in currencyNames, within which
|
||||
// range should the search be performed.
|
||||
// @param startPos: the comparison start position in text
|
||||
// @param textLen: the length of the text to be compared
|
||||
// @param maxMatchLen(IN/OUT): passing in the computed max matching length
|
||||
// pass out the new max matching length
|
||||
// @param maxMatchIndex: the index in currencyName which has the longest
|
||||
@ -1032,13 +1074,12 @@ binarySearch(const CurrencyNameStruct* currencyNames,
|
||||
static void
|
||||
linearSearch(const CurrencyNameStruct* currencyNames,
|
||||
int32_t begin, int32_t end,
|
||||
const UnicodeString* text, int32_t startPos,
|
||||
const UChar* text, int32_t textLen,
|
||||
int32_t *maxMatchLen, int32_t* maxMatchIndex) {
|
||||
for (int32_t index = begin; index <= end; ++index) {
|
||||
int32_t len = currencyNames[index].currencyNameLen;
|
||||
// TODO: case in-sensitve? but case-sensitive for ISO code /symbol?
|
||||
if (len > *maxMatchLen &&
|
||||
text->compare(startPos, len, currencyNames[index].currencyName) == 0) {
|
||||
if (len > *maxMatchLen && len <= textLen &&
|
||||
uprv_memcmp(currencyNames[index].currencyName, text, len * sizeof(UChar)) == 0) {
|
||||
*maxMatchIndex = index;
|
||||
*maxMatchLen = len;
|
||||
#ifdef UCURR_DEBUG
|
||||
@ -1053,7 +1094,7 @@ linearSearch(const CurrencyNameStruct* currencyNames,
|
||||
|
||||
// Find longest match between "text" and currency names in "currencyNames".
|
||||
// @param total_currency_count: total number of currency names in CurrencyNames.
|
||||
// @param start: the comparison start position in text
|
||||
// @param textLen: the length of the text to be compared
|
||||
// @param maxMatchLen: passing in the computed max matching length
|
||||
// pass out the new max matching length
|
||||
// @param maxMatchIndex: the index in currencyName which has the longest
|
||||
@ -1061,7 +1102,7 @@ linearSearch(const CurrencyNameStruct* currencyNames,
|
||||
static void
|
||||
searchCurrencyName(const CurrencyNameStruct* currencyNames,
|
||||
int32_t total_currency_count,
|
||||
const UnicodeString* text, int32_t start,
|
||||
const UChar* text, int32_t textLen,
|
||||
int32_t* maxMatchLen, int32_t* maxMatchIndex) {
|
||||
*maxMatchIndex = -1;
|
||||
*maxMatchLen = 0;
|
||||
@ -1082,25 +1123,25 @@ searchCurrencyName(const CurrencyNameStruct* currencyNames,
|
||||
// maximum matching).
|
||||
// The 4th round returns the same range (the maximum matching is "BBEX").
|
||||
// The 5th round returns no matching range.
|
||||
for (int32_t index = start; index < text->length(); ++index) {
|
||||
for (int32_t index = 0; index < textLen; ++index) {
|
||||
// matchIndex saves the one with exact match till the current point.
|
||||
// [binarySearchBegin, binarySearchEnd] saves the matching range.
|
||||
matchIndex = binarySearch(currencyNames, index - start,
|
||||
text, index,
|
||||
matchIndex = binarySearch(currencyNames, index,
|
||||
text[index],
|
||||
&binarySearchBegin, &binarySearchEnd);
|
||||
if (binarySearchBegin == -1) { // did not find the range
|
||||
break;
|
||||
}
|
||||
if (matchIndex != -1) {
|
||||
// find an exact match for text from text[start] to text[index]
|
||||
// find an exact match for text from text[0] to text[index]
|
||||
// in currencyNames array.
|
||||
*maxMatchLen = index - start + 1;
|
||||
*maxMatchLen = index + 1;
|
||||
*maxMatchIndex = matchIndex;
|
||||
}
|
||||
if (binarySearchEnd - binarySearchBegin < LINEAR_SEARCH_THRESHOLD) {
|
||||
// linear search if within threshold.
|
||||
linearSearch(currencyNames, binarySearchBegin, binarySearchEnd,
|
||||
text, start,
|
||||
text, textLen,
|
||||
maxMatchLen, maxMatchIndex);
|
||||
break;
|
||||
}
|
||||
@ -1111,8 +1152,12 @@ searchCurrencyName(const CurrencyNameStruct* currencyNames,
|
||||
//========================= currency name cache =====================
|
||||
typedef struct {
|
||||
char locale[ULOC_FULLNAME_CAPACITY]; //key
|
||||
// currency names, case insensitive
|
||||
CurrencyNameStruct* currencyNames; // value
|
||||
int32_t totalCurrencyNameCount; // currency name count
|
||||
// currency symbols and ISO code, case sensitive
|
||||
CurrencyNameStruct* currencySymbols; // value
|
||||
int32_t totalCurrencySymbolCount; // count
|
||||
// reference count.
|
||||
// reference count is set to 1 when an entry is put to cache.
|
||||
// it increases by 1 before accessing, and decreased by 1 after accessing.
|
||||
@ -1145,6 +1190,7 @@ deleteCurrencyNames(CurrencyNameStruct* currencyNames, int32_t count) {
|
||||
static void
|
||||
deleteCacheEntry(CurrencyNameCacheEntry* entry) {
|
||||
deleteCurrencyNames(entry->currencyNames, entry->totalCurrencyNameCount);
|
||||
deleteCurrencyNames(entry->currencySymbols, entry->totalCurrencySymbolCount);
|
||||
uprv_free(entry);
|
||||
}
|
||||
|
||||
@ -1166,6 +1212,7 @@ U_CFUNC void
|
||||
uprv_parseCurrency(const char* locale,
|
||||
const U_NAMESPACE_QUALIFIER UnicodeString& text,
|
||||
U_NAMESPACE_QUALIFIER ParsePosition& pos,
|
||||
int8_t type,
|
||||
UChar* result,
|
||||
UErrorCode& ec)
|
||||
{
|
||||
@ -1175,8 +1222,10 @@ uprv_parseCurrency(const char* locale,
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t total_currency_count = 0;
|
||||
int32_t total_currency_name_count = 0;
|
||||
CurrencyNameStruct* currencyNames = NULL;
|
||||
int32_t total_currency_symbol_count = 0;
|
||||
CurrencyNameStruct* currencySymbols = NULL;
|
||||
CurrencyNameCacheEntry* cacheEntry = NULL;
|
||||
|
||||
umtx_lock(NULL);
|
||||
@ -1193,12 +1242,14 @@ uprv_parseCurrency(const char* locale,
|
||||
if (found != -1) {
|
||||
cacheEntry = currCache[found];
|
||||
currencyNames = cacheEntry->currencyNames;
|
||||
total_currency_count = cacheEntry->totalCurrencyNameCount;
|
||||
total_currency_name_count = cacheEntry->totalCurrencyNameCount;
|
||||
currencySymbols = cacheEntry->currencySymbols;
|
||||
total_currency_symbol_count = cacheEntry->totalCurrencySymbolCount;
|
||||
++(cacheEntry->refCount);
|
||||
}
|
||||
umtx_unlock(NULL);
|
||||
if (found == -1) {
|
||||
currencyNames = collectCurrencyNames(locale, &total_currency_count, ec);
|
||||
collectCurrencyNames(locale, ¤cyNames, &total_currency_name_count, ¤cySymbols, &total_currency_symbol_count, ec);
|
||||
if (U_FAILURE(ec)) {
|
||||
return;
|
||||
}
|
||||
@ -1230,31 +1281,66 @@ uprv_parseCurrency(const char* locale,
|
||||
currCache[currentCacheEntryIndex] = cacheEntry;
|
||||
uprv_strcpy(cacheEntry->locale, locale);
|
||||
cacheEntry->currencyNames = currencyNames;
|
||||
cacheEntry->totalCurrencyNameCount = total_currency_count;
|
||||
cacheEntry->totalCurrencyNameCount = total_currency_name_count;
|
||||
cacheEntry->currencySymbols = currencySymbols;
|
||||
cacheEntry->totalCurrencySymbolCount = total_currency_symbol_count;
|
||||
cacheEntry->refCount = 2; // one for cache, one for reference
|
||||
currentCacheEntryIndex = (currentCacheEntryIndex + 1) % CURRENCY_NAME_CACHE_NUM;
|
||||
ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cache_cleanup);
|
||||
|
||||
} else {
|
||||
uprv_free(currencyNames);
|
||||
deleteCurrencyNames(currencyNames, total_currency_name_count);
|
||||
deleteCurrencyNames(currencySymbols, total_currency_symbol_count);
|
||||
cacheEntry = currCache[found];
|
||||
currencyNames = cacheEntry->currencyNames;
|
||||
total_currency_count = cacheEntry->totalCurrencyNameCount;
|
||||
total_currency_name_count = cacheEntry->totalCurrencyNameCount;
|
||||
currencySymbols = cacheEntry->currencySymbols;
|
||||
total_currency_symbol_count = cacheEntry->totalCurrencySymbolCount;
|
||||
++(cacheEntry->refCount);
|
||||
}
|
||||
umtx_unlock(NULL);
|
||||
}
|
||||
|
||||
int32_t start = pos.getIndex();
|
||||
|
||||
UChar inputText[MAX_CURRENCY_NAME_LEN];
|
||||
UChar upperText[MAX_CURRENCY_NAME_LEN];
|
||||
int32_t textLen = MIN(MAX_CURRENCY_NAME_LEN, text.length() - start);
|
||||
text.extract(start, textLen, inputText);
|
||||
UErrorCode ec1 = U_ZERO_ERROR;
|
||||
textLen = u_strToUpper(upperText, MAX_CURRENCY_NAME_LEN, inputText, textLen, NULL, &ec1);
|
||||
|
||||
int32_t max = 0;
|
||||
int32_t matchIndex = -1;
|
||||
int32_t start = pos.getIndex();
|
||||
searchCurrencyName(currencyNames, total_currency_count,
|
||||
&text, start, &max, &matchIndex);
|
||||
// case in-sensitive comparision against currency names
|
||||
searchCurrencyName(currencyNames, total_currency_name_count,
|
||||
upperText, textLen, &max, &matchIndex);
|
||||
|
||||
if (matchIndex != -1) {
|
||||
u_charsToUChars(currencyNames[matchIndex].IsoCode, result, 4);
|
||||
#ifdef UCURR_DEBUG
|
||||
printf("search in names, max = %d, matchIndex = %d\n", max, matchIndex);
|
||||
#endif
|
||||
|
||||
int32_t maxInSymbol = 0;
|
||||
int32_t matchIndexInSymbol = -1;
|
||||
if (type != UCURR_LONG_NAME) { // not name only
|
||||
// case sensitive comparison against currency symbols and ISO code.
|
||||
searchCurrencyName(currencySymbols, total_currency_symbol_count,
|
||||
inputText, textLen,
|
||||
&maxInSymbol, &matchIndexInSymbol);
|
||||
}
|
||||
|
||||
#ifdef UCURR_DEBUG
|
||||
printf("search in symbols, maxInSymbol = %d, matchIndexInSymbol = %d\n", maxInSymbol, matchIndexInSymbol);
|
||||
#endif
|
||||
|
||||
if (max >= maxInSymbol && matchIndex != -1) {
|
||||
u_charsToUChars(currencyNames[matchIndex].IsoCode, result, 4);
|
||||
pos.setIndex(start + max);
|
||||
} else if (maxInSymbol >= max && matchIndexInSymbol != -1) {
|
||||
u_charsToUChars(currencySymbols[matchIndexInSymbol].IsoCode, result, 4);
|
||||
pos.setIndex(start + maxInSymbol);
|
||||
}
|
||||
|
||||
// decrease reference count
|
||||
umtx_lock(NULL);
|
||||
--(cacheEntry->refCount);
|
||||
@ -1262,8 +1348,6 @@ uprv_parseCurrency(const char* locale,
|
||||
deleteCacheEntry(cacheEntry);
|
||||
}
|
||||
umtx_unlock(NULL);
|
||||
|
||||
pos.setIndex(start + max);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
**********************************************************************
|
||||
* Copyright (c) 2002-2008, International Business Machines
|
||||
* Copyright (c) 2002-2009, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
**********************************************************************
|
||||
*/
|
||||
@ -40,6 +40,7 @@ uprv_getStaticCurrencyName(const UChar* iso, const char* loc,
|
||||
* 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 type currency type to parse against, LONG_NAME only or not
|
||||
* @return the ISO 4217 code, as a string, of the best match, or
|
||||
* null if there is no match
|
||||
*
|
||||
@ -49,6 +50,7 @@ U_CFUNC void
|
||||
uprv_parseCurrency(const char* locale,
|
||||
const U_NAMESPACE_QUALIFIER UnicodeString& text,
|
||||
U_NAMESPACE_QUALIFIER ParsePosition& pos,
|
||||
int8_t type,
|
||||
UChar* result,
|
||||
UErrorCode& ec);
|
||||
|
||||
|
@ -1833,6 +1833,7 @@ private:
|
||||
const UnicodeString* posPrefix,
|
||||
const UnicodeString* posSuffix,
|
||||
UBool currencyParsing,
|
||||
int8_t type,
|
||||
ParsePosition& parsePosition,
|
||||
DigitList& digits, UBool* status,
|
||||
UChar* currency) const;
|
||||
@ -1856,6 +1857,7 @@ private:
|
||||
UBool isPrefix,
|
||||
const UnicodeString* affixPat,
|
||||
UBool currencyParsing,
|
||||
int8_t type,
|
||||
UChar* currency) const;
|
||||
|
||||
static int32_t compareSimpleAffix(const UnicodeString& affix,
|
||||
@ -1869,6 +1871,7 @@ private:
|
||||
int32_t compareComplexAffix(const UnicodeString& affixPat,
|
||||
const UnicodeString& input,
|
||||
int32_t pos,
|
||||
int8_t type,
|
||||
UChar* currency) const;
|
||||
|
||||
static int32_t match(const UnicodeString& text, int32_t pos, UChar32 ch);
|
||||
@ -2042,15 +2045,18 @@ private:
|
||||
UnicodeString posPrefixPatternForCurrency;
|
||||
// positive suffix pattern
|
||||
UnicodeString posSuffixPatternForCurrency;
|
||||
int8_t patternType;
|
||||
|
||||
AffixPatternsForCurrency(const UnicodeString& negPrefix,
|
||||
const UnicodeString& negSuffix,
|
||||
const UnicodeString& posPrefix,
|
||||
const UnicodeString& posSuffix) {
|
||||
const UnicodeString& posSuffix,
|
||||
int8_t type) {
|
||||
negPrefixPatternForCurrency = negPrefix;
|
||||
negSuffixPatternForCurrency = negSuffix;
|
||||
posPrefixPatternForCurrency = posPrefix;
|
||||
posSuffixPatternForCurrency = posSuffix;
|
||||
patternType = type;
|
||||
}
|
||||
};
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user