mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-13 08:53:20 +00:00
ICU-21254 Add plural rule parsing for exponent operand in C++
This commit is contained in:
parent
82545ecc2c
commit
cb7f197821
4 changed files with 99 additions and 0 deletions
icu4c/source
|
@ -56,6 +56,7 @@ static const UChar PK_VAR_N[]={LOW_N,0};
|
|||
static const UChar PK_VAR_I[]={LOW_I,0};
|
||||
static const UChar PK_VAR_F[]={LOW_F,0};
|
||||
static const UChar PK_VAR_T[]={LOW_T,0};
|
||||
static const UChar PK_VAR_E[]={LOW_E,0};
|
||||
static const UChar PK_VAR_V[]={LOW_V,0};
|
||||
static const UChar PK_WITHIN[]={LOW_W,LOW_I,LOW_T,LOW_H,LOW_I,LOW_N,0};
|
||||
static const UChar PK_DECIMAL[]={LOW_D,LOW_E,LOW_C,LOW_I,LOW_M,LOW_A,LOW_L,0};
|
||||
|
@ -600,6 +601,7 @@ PluralRuleParser::parse(const UnicodeString& ruleData, PluralRules *prules, UErr
|
|||
case tVariableI:
|
||||
case tVariableF:
|
||||
case tVariableT:
|
||||
case tVariableE:
|
||||
case tVariableV:
|
||||
U_ASSERT(curAndConstraint != nullptr);
|
||||
curAndConstraint->digitsType = type;
|
||||
|
@ -984,6 +986,8 @@ static UnicodeString tokenString(tokenType tok) {
|
|||
s.append(LOW_V); break;
|
||||
case tVariableT:
|
||||
s.append(LOW_T); break;
|
||||
case tVariableE:
|
||||
s.append(LOW_E); break;
|
||||
default:
|
||||
s.append(TILDE);
|
||||
}
|
||||
|
@ -1160,6 +1164,7 @@ PluralRuleParser::checkSyntax(UErrorCode &status)
|
|||
case tVariableI:
|
||||
case tVariableF:
|
||||
case tVariableT:
|
||||
case tVariableE:
|
||||
case tVariableV:
|
||||
if (type != tIs && type != tMod && type != tIn &&
|
||||
type != tNot && type != tWithin && type != tEqual && type != tNotEqual) {
|
||||
|
@ -1176,6 +1181,7 @@ PluralRuleParser::checkSyntax(UErrorCode &status)
|
|||
type == tVariableI ||
|
||||
type == tVariableF ||
|
||||
type == tVariableT ||
|
||||
type == tVariableE ||
|
||||
type == tVariableV ||
|
||||
type == tAt)) {
|
||||
status = U_UNEXPECTED_TOKEN;
|
||||
|
@ -1207,6 +1213,7 @@ PluralRuleParser::checkSyntax(UErrorCode &status)
|
|||
type != tVariableI &&
|
||||
type != tVariableF &&
|
||||
type != tVariableT &&
|
||||
type != tVariableE &&
|
||||
type != tVariableV) {
|
||||
status = U_UNEXPECTED_TOKEN;
|
||||
}
|
||||
|
@ -1384,6 +1391,8 @@ PluralRuleParser::getKeyType(const UnicodeString &token, tokenType keyType)
|
|||
keyType = tVariableF;
|
||||
} else if (0 == token.compare(PK_VAR_T, 1)) {
|
||||
keyType = tVariableT;
|
||||
} else if (0 == token.compare(PK_VAR_E, 1)) {
|
||||
keyType = tVariableE;
|
||||
} else if (0 == token.compare(PK_VAR_V, 1)) {
|
||||
keyType = tVariableV;
|
||||
} else if (0 == token.compare(PK_IS, 2)) {
|
||||
|
@ -1481,6 +1490,8 @@ PluralOperand tokenTypeToPluralOperand(tokenType tt) {
|
|||
return PLURAL_OPERAND_V;
|
||||
case tVariableT:
|
||||
return PLURAL_OPERAND_T;
|
||||
case tVariableE:
|
||||
return PLURAL_OPERAND_E;
|
||||
default:
|
||||
UPRV_UNREACHABLE; // unexpected.
|
||||
}
|
||||
|
|
|
@ -138,6 +138,7 @@ enum tokenType {
|
|||
tVariableF,
|
||||
tVariableV,
|
||||
tVariableT,
|
||||
tVariableE,
|
||||
tDecimal,
|
||||
tInteger,
|
||||
tEOF
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "number_decimalquantity.h"
|
||||
|
||||
using icu::number::impl::DecimalQuantity;
|
||||
using namespace icu::number;
|
||||
|
||||
void setupResult(const int32_t testSource[], char result[], int32_t* max);
|
||||
UBool checkEqual(const PluralRules &test, char *result, int32_t max);
|
||||
|
@ -49,6 +50,7 @@ void PluralRulesTest::runIndexedTest( int32_t index, UBool exec, const char* &na
|
|||
TESTCASE_AUTO(testGetSamples);
|
||||
TESTCASE_AUTO(testWithin);
|
||||
TESTCASE_AUTO(testGetAllKeywordValues);
|
||||
TESTCASE_AUTO(testCompactDecimalPluralKeyword);
|
||||
TESTCASE_AUTO(testOrdinal);
|
||||
TESTCASE_AUTO(testSelect);
|
||||
TESTCASE_AUTO(testAvailbleLocales);
|
||||
|
@ -595,6 +597,88 @@ PluralRulesTest::testGetAllKeywordValues() {
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
PluralRulesTest::testCompactDecimalPluralKeyword() {
|
||||
IcuTestErrorCode errorCode(*this, "testCompactDecimalPluralKeyword");
|
||||
|
||||
LocalPointer<PluralRules> rules(PluralRules::createRules(
|
||||
u"one: i = 0,1 @integer 0, 1 @decimal 0.0~1.5; "
|
||||
u"many: e = 0 and i % 1000000 = 0 and v = 0 or e != 0 .. 5; "
|
||||
u"other: @integer 2~17, 100, 1000, 10000, 100000, 1000000, "
|
||||
u" @decimal 2.0~3.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …", errorCode));
|
||||
|
||||
if (U_FAILURE(errorCode)) {
|
||||
errln("Couldn't instantiate plurals rules from string, with error = %s", u_errorName(errorCode));
|
||||
return;
|
||||
}
|
||||
|
||||
const char* localeName = "fr-FR";
|
||||
Locale locale = Locale::createFromName(localeName);
|
||||
|
||||
struct TestCase {
|
||||
const char16_t* skeleton;
|
||||
const int input;
|
||||
const char16_t* expectedFormattedOutput;
|
||||
const char16_t* expectedPluralRuleKeyword;
|
||||
} cases[] = {
|
||||
// unlocalized formatter skeleton, input, string output, plural rule keyword
|
||||
{u"", 0, u"0", u"one"},
|
||||
{u"compact-long", 0, u"0", u"one"},
|
||||
|
||||
{u"", 1, u"1", u"one"},
|
||||
{u"compact-long", 1, u"1", u"one"},
|
||||
|
||||
{u"", 2, u"2", u"other"},
|
||||
{u"compact-long", 2, u"2", u"other"},
|
||||
|
||||
{u"", 1000000, u"1 000 000", u"many"},
|
||||
{u"compact-long", 1000000, u"1 million", u"many"},
|
||||
|
||||
{u"", 1000001, u"1 000 001", u"other"},
|
||||
{u"compact-long", 1000001, u"1 million", u"many"},
|
||||
|
||||
{u"", 120000, u"1 200 000", u"other"},
|
||||
{u"compact-long", 1200000, u"1,2 millions", u"many"},
|
||||
|
||||
{u"", 1200001, u"1 200 001", u"other"},
|
||||
{u"compact-long", 1200001, u"1,2 millions", u"many"},
|
||||
|
||||
{u"", 2000000, u"2 000 000", u"many"},
|
||||
{u"compact-long", 2000000, u"2 millions", u"many"},
|
||||
};
|
||||
for (const auto& cas : cases) {
|
||||
const char16_t* skeleton = cas.skeleton;
|
||||
const int input = cas.input;
|
||||
const char16_t* expectedPluralRuleKeyword = cas.expectedPluralRuleKeyword;
|
||||
|
||||
UnicodeString actualPluralRuleKeyword =
|
||||
getPluralKeyword(rules, locale, input, skeleton);
|
||||
|
||||
UnicodeString message(UnicodeString(localeName) + u" " + DoubleToUnicodeString(input));
|
||||
assertEquals(message, expectedPluralRuleKeyword, actualPluralRuleKeyword);
|
||||
}
|
||||
}
|
||||
|
||||
UnicodeString PluralRulesTest::getPluralKeyword(const LocalPointer<PluralRules> &rules, Locale locale, double number, const char16_t* skeleton) {
|
||||
IcuTestErrorCode errorCode(*this, "getPluralKeyword");
|
||||
UnlocalizedNumberFormatter ulnf = NumberFormatter::forSkeleton(skeleton, errorCode);
|
||||
if (errorCode.errIfFailureAndReset("PluralRules::getPluralKeyword(<PluralRules>, <locale>, %d, %s) failed", number, skeleton)) {
|
||||
return nullptr;
|
||||
}
|
||||
LocalizedNumberFormatter formatter = ulnf.locale(locale);
|
||||
|
||||
const FormattedNumber fn = formatter.formatDouble(number, errorCode);
|
||||
if (errorCode.errIfFailureAndReset("NumberFormatter::formatDouble(%d) failed", number)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UnicodeString pluralKeyword = rules->select(fn, errorCode);
|
||||
if (errorCode.errIfFailureAndReset("PluralRules->select(FormattedNumber of %d) failed", number)) {
|
||||
return nullptr;
|
||||
}
|
||||
return pluralKeyword;
|
||||
}
|
||||
|
||||
void PluralRulesTest::testOrdinal() {
|
||||
IcuTestErrorCode errorCode(*this, "testOrdinal");
|
||||
LocalPointer<PluralRules> pr(PluralRules::forLocale("en", UPLURAL_TYPE_ORDINAL, errorCode));
|
||||
|
|
|
@ -32,6 +32,7 @@ private:
|
|||
void testGetSamples();
|
||||
void testWithin();
|
||||
void testGetAllKeywordValues();
|
||||
void testCompactDecimalPluralKeyword();
|
||||
void testOrdinal();
|
||||
void testSelect();
|
||||
void testAvailbleLocales();
|
||||
|
@ -43,6 +44,8 @@ private:
|
|||
void assertRuleValue(const UnicodeString& rule, double expected);
|
||||
void assertRuleKeyValue(const UnicodeString& rule, const UnicodeString& key,
|
||||
double expected);
|
||||
UnicodeString getPluralKeyword(const LocalPointer<PluralRules> &rules,
|
||||
Locale locale, double number, const char16_t* skeleton);
|
||||
void checkSelect(const LocalPointer<PluralRules> &rules, UErrorCode &status,
|
||||
int32_t line, const char *keyword, ...);
|
||||
void compareLocaleResults(const char* loc1, const char* loc2, const char* loc3);
|
||||
|
|
Loading…
Add table
Reference in a new issue