| OLD | NEW |
| 1 /* | 1 /* |
| 2 ****************************************************************************** | 2 ****************************************************************************** |
| 3 * Copyright (C) 1997-2011, International Business Machines | 3 * Copyright (C) 1997-2014, International Business Machines |
| 4 * Corporation and others. All Rights Reserved. | 4 * Corporation and others. All Rights Reserved. |
| 5 ****************************************************************************** | 5 ****************************************************************************** |
| 6 * file name: nfrule.cpp | 6 * file name: nfrule.cpp |
| 7 * encoding: US-ASCII | 7 * encoding: US-ASCII |
| 8 * tab size: 8 (not used) | 8 * tab size: 8 (not used) |
| 9 * indentation:4 | 9 * indentation:4 |
| 10 * | 10 * |
| 11 * Modification history | 11 * Modification history |
| 12 * Date Name Comments | 12 * Date Name Comments |
| 13 * 10/11/2001 Doug Ported from ICU4J | 13 * 10/11/2001 Doug Ported from ICU4J |
| 14 */ | 14 */ |
| 15 | 15 |
| 16 #include "nfrule.h" | 16 #include "nfrule.h" |
| 17 | 17 |
| 18 #if U_HAVE_RBNF | 18 #if U_HAVE_RBNF |
| 19 | 19 |
| 20 #include "unicode/localpointer.h" |
| 20 #include "unicode/rbnf.h" | 21 #include "unicode/rbnf.h" |
| 21 #include "unicode/tblcoll.h" | 22 #include "unicode/tblcoll.h" |
| 23 #include "unicode/plurfmt.h" |
| 24 #include "unicode/upluralrules.h" |
| 22 #include "unicode/coleitr.h" | 25 #include "unicode/coleitr.h" |
| 23 #include "unicode/uchar.h" | 26 #include "unicode/uchar.h" |
| 24 #include "nfrs.h" | 27 #include "nfrs.h" |
| 25 #include "nfrlist.h" | 28 #include "nfrlist.h" |
| 26 #include "nfsubs.h" | 29 #include "nfsubs.h" |
| 27 #include "patternprops.h" | 30 #include "patternprops.h" |
| 28 | 31 |
| 29 U_NAMESPACE_BEGIN | 32 U_NAMESPACE_BEGIN |
| 30 | 33 |
| 31 NFRule::NFRule(const RuleBasedNumberFormat* _rbnf) | 34 NFRule::NFRule(const RuleBasedNumberFormat* _rbnf) |
| 32 : baseValue((int32_t)0) | 35 : baseValue((int32_t)0) |
| 33 , radix(0) | 36 , radix(0) |
| 34 , exponent(0) | 37 , exponent(0) |
| 35 , ruleText() | 38 , ruleText() |
| 36 , sub1(NULL) | 39 , sub1(NULL) |
| 37 , sub2(NULL) | 40 , sub2(NULL) |
| 38 , formatter(_rbnf) | 41 , formatter(_rbnf) |
| 42 , rulePatternFormat(NULL) |
| 39 { | 43 { |
| 40 } | 44 } |
| 41 | 45 |
| 42 NFRule::~NFRule() | 46 NFRule::~NFRule() |
| 43 { | 47 { |
| 44 delete sub1; | 48 if (sub1 != sub2) { |
| 45 delete sub2; | 49 delete sub2; |
| 50 } |
| 51 delete sub1; |
| 52 delete rulePatternFormat; |
| 46 } | 53 } |
| 47 | 54 |
| 48 static const UChar gLeftBracket = 0x005b; | 55 static const UChar gLeftBracket = 0x005b; |
| 49 static const UChar gRightBracket = 0x005d; | 56 static const UChar gRightBracket = 0x005d; |
| 50 static const UChar gColon = 0x003a; | 57 static const UChar gColon = 0x003a; |
| 51 static const UChar gZero = 0x0030; | 58 static const UChar gZero = 0x0030; |
| 52 static const UChar gNine = 0x0039; | 59 static const UChar gNine = 0x0039; |
| 53 static const UChar gSpace = 0x0020; | 60 static const UChar gSpace = 0x0020; |
| 54 static const UChar gSlash = 0x002f; | 61 static const UChar gSlash = 0x002f; |
| 55 static const UChar gGreaterThan = 0x003e; | 62 static const UChar gGreaterThan = 0x003e; |
| 56 static const UChar gLessThan = 0x003c; | 63 static const UChar gLessThan = 0x003c; |
| 57 static const UChar gComma = 0x002c; | 64 static const UChar gComma = 0x002c; |
| 58 static const UChar gDot = 0x002e; | 65 static const UChar gDot = 0x002e; |
| 59 static const UChar gTick = 0x0027; | 66 static const UChar gTick = 0x0027; |
| 60 //static const UChar gMinus = 0x002d; | 67 //static const UChar gMinus = 0x002d; |
| 61 static const UChar gSemicolon = 0x003b; | 68 static const UChar gSemicolon = 0x003b; |
| 62 | 69 |
| 63 static const UChar gMinusX[] = {0x2D, 0x78, 0}; /* "-x" */ | 70 static const UChar gMinusX[] = {0x2D, 0x78, 0}; /* "-x" */ |
| 64 static const UChar gXDotX[] = {0x78, 0x2E, 0x78, 0}; /* "x.x"
*/ | 71 static const UChar gXDotX[] = {0x78, 0x2E, 0x78, 0}; /* "x.x"
*/ |
| 65 static const UChar gXDotZero[] = {0x78, 0x2E, 0x30, 0}; /* "x.0"
*/ | 72 static const UChar gXDotZero[] = {0x78, 0x2E, 0x30, 0}; /* "x.0"
*/ |
| 66 static const UChar gZeroDotX[] = {0x30, 0x2E, 0x78, 0}; /* "0.x"
*/ | 73 static const UChar gZeroDotX[] = {0x30, 0x2E, 0x78, 0}; /* "0.x"
*/ |
| 67 | 74 |
| 75 static const UChar gDollarOpenParenthesis[] = {0x24, 0x28, 0}; /* "$(" */ |
| 76 static const UChar gClosedParenthesisDollar[] = {0x29, 0x24, 0}; /* ")$" */ |
| 77 |
| 68 static const UChar gLessLess[] = {0x3C, 0x3C, 0}; /* "<<" */ | 78 static const UChar gLessLess[] = {0x3C, 0x3C, 0}; /* "<<" */ |
| 69 static const UChar gLessPercent[] = {0x3C, 0x25, 0}; /* "<%" */ | 79 static const UChar gLessPercent[] = {0x3C, 0x25, 0}; /* "<%" */ |
| 70 static const UChar gLessHash[] = {0x3C, 0x23, 0}; /* "<#" */ | 80 static const UChar gLessHash[] = {0x3C, 0x23, 0}; /* "<#" */ |
| 71 static const UChar gLessZero[] = {0x3C, 0x30, 0}; /* "<0" */ | 81 static const UChar gLessZero[] = {0x3C, 0x30, 0}; /* "<0" */ |
| 72 static const UChar gGreaterGreater[] = {0x3E, 0x3E, 0}; /* ">>" */ | 82 static const UChar gGreaterGreater[] = {0x3E, 0x3E, 0}; /* ">>" */ |
| 73 static const UChar gGreaterPercent[] = {0x3E, 0x25, 0}; /* ">%" */ | 83 static const UChar gGreaterPercent[] = {0x3E, 0x25, 0}; /* ">%" */ |
| 74 static const UChar gGreaterHash[] = {0x3E, 0x23, 0}; /* ">#" */ | 84 static const UChar gGreaterHash[] = {0x3E, 0x23, 0}; /* ">#" */ |
| 75 static const UChar gGreaterZero[] = {0x3E, 0x30, 0}; /* ">0" */ | 85 static const UChar gGreaterZero[] = {0x3E, 0x30, 0}; /* ">0" */ |
| 76 static const UChar gEqualPercent[] = {0x3D, 0x25, 0}; /* "=%" */ | 86 static const UChar gEqualPercent[] = {0x3D, 0x25, 0}; /* "=%" */ |
| 77 static const UChar gEqualHash[] = {0x3D, 0x23, 0}; /* "=#" */ | 87 static const UChar gEqualHash[] = {0x3D, 0x23, 0}; /* "=#" */ |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 109 int32_t brack1 = description.indexOf(gLeftBracket); | 119 int32_t brack1 = description.indexOf(gLeftBracket); |
| 110 int32_t brack2 = description.indexOf(gRightBracket); | 120 int32_t brack2 = description.indexOf(gRightBracket); |
| 111 | 121 |
| 112 // if the description doesn't contain a matched pair of brackets, | 122 // if the description doesn't contain a matched pair of brackets, |
| 113 // or if it's of a type that doesn't recognize bracketed text, | 123 // or if it's of a type that doesn't recognize bracketed text, |
| 114 // then leave the description alone, initialize the rule's | 124 // then leave the description alone, initialize the rule's |
| 115 // rule text and substitutions, and return that rule | 125 // rule text and substitutions, and return that rule |
| 116 if (brack1 == -1 || brack2 == -1 || brack1 > brack2 | 126 if (brack1 == -1 || brack2 == -1 || brack1 > brack2 |
| 117 || rule1->getType() == kProperFractionRule | 127 || rule1->getType() == kProperFractionRule |
| 118 || rule1->getType() == kNegativeNumberRule) { | 128 || rule1->getType() == kNegativeNumberRule) { |
| 119 rule1->ruleText = description; | 129 rule1->extractSubstitutions(ruleSet, description, predecessor, status); |
| 120 rule1->extractSubstitutions(ruleSet, predecessor, rbnf, status); | |
| 121 rules.add(rule1); | 130 rules.add(rule1); |
| 122 } else { | 131 } else { |
| 123 // if the description does contain a matched pair of brackets, | 132 // if the description does contain a matched pair of brackets, |
| 124 // then it's really shorthand for two rules (with one exception) | 133 // then it's really shorthand for two rules (with one exception) |
| 125 NFRule* rule2 = NULL; | 134 NFRule* rule2 = NULL; |
| 126 UnicodeString sbuf; | 135 UnicodeString sbuf; |
| 127 | 136 |
| 128 // we'll actually only split the rule into two rules if its | 137 // we'll actually only split the rule into two rules if its |
| 129 // base value is an even multiple of its divisor (or it's one | 138 // base value is an even multiple of its divisor (or it's one |
| 130 // of the special rules) | 139 // of the special rules) |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 170 // same divisor) | 179 // same divisor) |
| 171 rule2->radix = rule1->radix; | 180 rule2->radix = rule1->radix; |
| 172 rule2->exponent = rule1->exponent; | 181 rule2->exponent = rule1->exponent; |
| 173 | 182 |
| 174 // rule2's rule text omits the stuff in brackets: initalize | 183 // rule2's rule text omits the stuff in brackets: initalize |
| 175 // its rule text and substitutions accordingly | 184 // its rule text and substitutions accordingly |
| 176 sbuf.append(description, 0, brack1); | 185 sbuf.append(description, 0, brack1); |
| 177 if (brack2 + 1 < description.length()) { | 186 if (brack2 + 1 < description.length()) { |
| 178 sbuf.append(description, brack2 + 1, description.length() - brac
k2 - 1); | 187 sbuf.append(description, brack2 + 1, description.length() - brac
k2 - 1); |
| 179 } | 188 } |
| 180 rule2->ruleText.setTo(sbuf); | 189 rule2->extractSubstitutions(ruleSet, sbuf, predecessor, status); |
| 181 rule2->extractSubstitutions(ruleSet, predecessor, rbnf, status); | |
| 182 } | 190 } |
| 183 | 191 |
| 184 // rule1's text includes the text in the brackets but omits | 192 // rule1's text includes the text in the brackets but omits |
| 185 // the brackets themselves: initialize _its_ rule text and | 193 // the brackets themselves: initialize _its_ rule text and |
| 186 // substitutions accordingly | 194 // substitutions accordingly |
| 187 sbuf.setTo(description, 0, brack1); | 195 sbuf.setTo(description, 0, brack1); |
| 188 sbuf.append(description, brack1 + 1, brack2 - brack1 - 1); | 196 sbuf.append(description, brack1 + 1, brack2 - brack1 - 1); |
| 189 if (brack2 + 1 < description.length()) { | 197 if (brack2 + 1 < description.length()) { |
| 190 sbuf.append(description, brack2 + 1, description.length() - brack2 -
1); | 198 sbuf.append(description, brack2 + 1, description.length() - brack2 -
1); |
| 191 } | 199 } |
| 192 rule1->ruleText.setTo(sbuf); | 200 rule1->extractSubstitutions(ruleSet, sbuf, predecessor, status); |
| 193 rule1->extractSubstitutions(ruleSet, predecessor, rbnf, status); | |
| 194 | 201 |
| 195 // if we only have one rule, return it; if we have two, return | 202 // if we only have one rule, return it; if we have two, return |
| 196 // a two-element array containing them (notice that rule2 goes | 203 // a two-element array containing them (notice that rule2 goes |
| 197 // BEFORE rule1 in the list: in all cases, rule2 OMITS the | 204 // BEFORE rule1 in the list: in all cases, rule2 OMITS the |
| 198 // material in the brackets and rule1 INCLUDES the material | 205 // material in the brackets and rule1 INCLUDES the material |
| 199 // in the brackets) | 206 // in the brackets) |
| 200 if (rule2 != NULL) { | 207 if (rule2 != NULL) { |
| 201 rules.add(rule2); | 208 rules.add(rule2); |
| 202 } | 209 } |
| 203 rules.add(rule1); | 210 rules.add(rule1); |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 362 /** | 369 /** |
| 363 * Searches the rule's rule text for the substitution tokens, | 370 * Searches the rule's rule text for the substitution tokens, |
| 364 * creates the substitutions, and removes the substitution tokens | 371 * creates the substitutions, and removes the substitution tokens |
| 365 * from the rule's rule text. | 372 * from the rule's rule text. |
| 366 * @param owner The rule set containing this rule | 373 * @param owner The rule set containing this rule |
| 367 * @param predecessor The rule preseding this one in "owners" rule list | 374 * @param predecessor The rule preseding this one in "owners" rule list |
| 368 * @param ownersOwner The RuleBasedFormat that owns this rule | 375 * @param ownersOwner The RuleBasedFormat that owns this rule |
| 369 */ | 376 */ |
| 370 void | 377 void |
| 371 NFRule::extractSubstitutions(const NFRuleSet* ruleSet, | 378 NFRule::extractSubstitutions(const NFRuleSet* ruleSet, |
| 379 const UnicodeString &ruleText, |
| 372 const NFRule* predecessor, | 380 const NFRule* predecessor, |
| 373 const RuleBasedNumberFormat* rbnf, | |
| 374 UErrorCode& status) | 381 UErrorCode& status) |
| 375 { | 382 { |
| 376 if (U_SUCCESS(status)) { | 383 if (U_FAILURE(status)) { |
| 377 sub1 = extractSubstitution(ruleSet, predecessor, rbnf, status); | 384 return; |
| 378 sub2 = extractSubstitution(ruleSet, predecessor, rbnf, status); | 385 } |
| 386 this->ruleText = ruleText; |
| 387 this->rulePatternFormat = NULL; |
| 388 sub1 = extractSubstitution(ruleSet, predecessor, status); |
| 389 if (sub1 == NULL || sub1->isNullSubstitution()) { |
| 390 // Small optimization. There is no need to create a redundant NullSubsti
tution. |
| 391 sub2 = sub1; |
| 392 } |
| 393 else { |
| 394 sub2 = extractSubstitution(ruleSet, predecessor, status); |
| 395 } |
| 396 int32_t pluralRuleStart = this->ruleText.indexOf(gDollarOpenParenthesis, -1,
0); |
| 397 int32_t pluralRuleEnd = (pluralRuleStart >= 0 ? this->ruleText.indexOf(gClos
edParenthesisDollar, -1, pluralRuleStart) : -1); |
| 398 if (pluralRuleEnd >= 0) { |
| 399 int32_t endType = this->ruleText.indexOf(gComma, pluralRuleStart); |
| 400 if (endType < 0) { |
| 401 status = U_PARSE_ERROR; |
| 402 return; |
| 403 } |
| 404 UnicodeString type(this->ruleText.tempSubString(pluralRuleStart + 2, end
Type - pluralRuleStart - 2)); |
| 405 UPluralType pluralType; |
| 406 if (type.startsWith(UNICODE_STRING_SIMPLE("cardinal"))) { |
| 407 pluralType = UPLURAL_TYPE_CARDINAL; |
| 408 } |
| 409 else if (type.startsWith(UNICODE_STRING_SIMPLE("ordinal"))) { |
| 410 pluralType = UPLURAL_TYPE_ORDINAL; |
| 411 } |
| 412 else { |
| 413 status = U_ILLEGAL_ARGUMENT_ERROR; |
| 414 return; |
| 415 } |
| 416 rulePatternFormat = formatter->createPluralFormat(pluralType, |
| 417 this->ruleText.tempSubString(endType + 1, pluralRuleEnd - endTyp
e - 1), status); |
| 379 } | 418 } |
| 380 } | 419 } |
| 381 | 420 |
| 382 /** | 421 /** |
| 383 * Searches the rule's rule text for the first substitution token, | 422 * Searches the rule's rule text for the first substitution token, |
| 384 * creates a substitution based on it, and removes the token from | 423 * creates a substitution based on it, and removes the token from |
| 385 * the rule's rule text. | 424 * the rule's rule text. |
| 386 * @param owner The rule set containing this rule | 425 * @param owner The rule set containing this rule |
| 387 * @param predecessor The rule preceding this one in the rule set's | 426 * @param predecessor The rule preceding this one in the rule set's |
| 388 * rule list | 427 * rule list |
| 389 * @param ownersOwner The RuleBasedNumberFormat that owns this rule | 428 * @param ownersOwner The RuleBasedNumberFormat that owns this rule |
| 390 * @return The newly-created substitution. This is never null; if | 429 * @return The newly-created substitution. This is never null; if |
| 391 * the rule text doesn't contain any substitution tokens, this will | 430 * the rule text doesn't contain any substitution tokens, this will |
| 392 * be a NullSubstitution. | 431 * be a NullSubstitution. |
| 393 */ | 432 */ |
| 394 NFSubstitution * | 433 NFSubstitution * |
| 395 NFRule::extractSubstitution(const NFRuleSet* ruleSet, | 434 NFRule::extractSubstitution(const NFRuleSet* ruleSet, |
| 396 const NFRule* predecessor, | 435 const NFRule* predecessor, |
| 397 const RuleBasedNumberFormat* rbnf, | |
| 398 UErrorCode& status) | 436 UErrorCode& status) |
| 399 { | 437 { |
| 400 NFSubstitution* result = NULL; | 438 NFSubstitution* result = NULL; |
| 401 | 439 |
| 402 // search the rule's rule text for the first two characters of | 440 // search the rule's rule text for the first two characters of |
| 403 // a substitution token | 441 // a substitution token |
| 404 int32_t subStart = indexOfAny(tokenStrings); | 442 int32_t subStart = indexOfAny(tokenStrings); |
| 405 int32_t subEnd = subStart; | 443 int32_t subEnd = subStart; |
| 406 | 444 |
| 407 // if we didn't find one, create a null substitution positioned | 445 // if we didn't find one, create a null substitution positioned |
| 408 // at the end of the rule text | 446 // at the end of the rule text |
| 409 if (subStart == -1) { | 447 if (subStart == -1) { |
| 410 return NFSubstitution::makeSubstitution(ruleText.length(), this, predece
ssor, | 448 return NFSubstitution::makeSubstitution(ruleText.length(), this, predece
ssor, |
| 411 ruleSet, rbnf, UnicodeString(), status); | 449 ruleSet, this->formatter, UnicodeString(), status); |
| 412 } | 450 } |
| 413 | 451 |
| 414 // special-case the ">>>" token, since searching for the > at the | 452 // special-case the ">>>" token, since searching for the > at the |
| 415 // end will actually find the > in the middle | 453 // end will actually find the > in the middle |
| 416 if (ruleText.indexOf(gGreaterGreaterGreater, 3, 0) == subStart) { | 454 if (ruleText.indexOf(gGreaterGreaterGreater, 3, 0) == subStart) { |
| 417 subEnd = subStart + 2; | 455 subEnd = subStart + 2; |
| 418 | 456 |
| 419 // otherwise the substitution token ends with the same character | 457 // otherwise the substitution token ends with the same character |
| 420 // it began with | 458 // it began with |
| 421 } else { | 459 } else { |
| 422 UChar c = ruleText.charAt(subStart); | 460 UChar c = ruleText.charAt(subStart); |
| 423 subEnd = ruleText.indexOf(c, subStart + 1); | 461 subEnd = ruleText.indexOf(c, subStart + 1); |
| 424 // special case for '<%foo<<' | 462 // special case for '<%foo<<' |
| 425 if (c == gLessThan && subEnd != -1 && subEnd < ruleText.length() - 1 &&
ruleText.charAt(subEnd+1) == c) { | 463 if (c == gLessThan && subEnd != -1 && subEnd < ruleText.length() - 1 &&
ruleText.charAt(subEnd+1) == c) { |
| 426 // ordinals use "=#,##0==%abbrev=" as their rule. Notice that the '
==' in the middle | 464 // ordinals use "=#,##0==%abbrev=" as their rule. Notice that the '
==' in the middle |
| 427 // occurs because of the juxtaposition of two different rules. The
check for '<' is a hack | 465 // occurs because of the juxtaposition of two different rules. The
check for '<' is a hack |
| 428 // to get around this. Having the duplicate at the front would caus
e problems with | 466 // to get around this. Having the duplicate at the front would caus
e problems with |
| 429 // rules like "<<%" to format, say, percents... | 467 // rules like "<<%" to format, say, percents... |
| 430 ++subEnd; | 468 ++subEnd; |
| 431 } | 469 } |
| 432 } | 470 } |
| 433 | 471 |
| 434 // if we don't find the end of the token (i.e., if we're on a single, | 472 // if we don't find the end of the token (i.e., if we're on a single, |
| 435 // unmatched token character), create a null substitution positioned | 473 // unmatched token character), create a null substitution positioned |
| 436 // at the end of the rule | 474 // at the end of the rule |
| 437 if (subEnd == -1) { | 475 if (subEnd == -1) { |
| 438 return NFSubstitution::makeSubstitution(ruleText.length(), this, predece
ssor, | 476 return NFSubstitution::makeSubstitution(ruleText.length(), this, predece
ssor, |
| 439 ruleSet, rbnf, UnicodeString(), status); | 477 ruleSet, this->formatter, UnicodeString(), status); |
| 440 } | 478 } |
| 441 | 479 |
| 442 // if we get here, we have a real substitution token (or at least | 480 // if we get here, we have a real substitution token (or at least |
| 443 // some text bounded by substitution token characters). Use | 481 // some text bounded by substitution token characters). Use |
| 444 // makeSubstitution() to create the right kind of substitution | 482 // makeSubstitution() to create the right kind of substitution |
| 445 UnicodeString subToken; | 483 UnicodeString subToken; |
| 446 subToken.setTo(ruleText, subStart, subEnd + 1 - subStart); | 484 subToken.setTo(ruleText, subStart, subEnd + 1 - subStart); |
| 447 result = NFSubstitution::makeSubstitution(subStart, this, predecessor, ruleS
et, | 485 result = NFSubstitution::makeSubstitution(subStart, this, predecessor, ruleS
et, |
| 448 rbnf, subToken, status); | 486 this->formatter, subToken, status); |
| 449 | 487 |
| 450 // remove the substitution from the rule text | 488 // remove the substitution from the rule text |
| 451 ruleText.removeBetween(subStart, subEnd+1); | 489 ruleText.removeBetween(subStart, subEnd+1); |
| 452 | 490 |
| 453 return result; | 491 return result; |
| 454 } | 492 } |
| 455 | 493 |
| 456 /** | 494 /** |
| 457 * Sets the rule's base value, and causes the radix and exponent | 495 * Sets the rule's base value, and causes the radix and exponent |
| 458 * to be recalculated. This is used during construction when we | 496 * to be recalculated. This is used during construction when we |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 637 /** | 675 /** |
| 638 * Formats the number, and inserts the resulting text into | 676 * Formats the number, and inserts the resulting text into |
| 639 * toInsertInto. | 677 * toInsertInto. |
| 640 * @param number The number being formatted | 678 * @param number The number being formatted |
| 641 * @param toInsertInto The string where the resultant text should | 679 * @param toInsertInto The string where the resultant text should |
| 642 * be inserted | 680 * be inserted |
| 643 * @param pos The position in toInsertInto where the resultant text | 681 * @param pos The position in toInsertInto where the resultant text |
| 644 * should be inserted | 682 * should be inserted |
| 645 */ | 683 */ |
| 646 void | 684 void |
| 647 NFRule::doFormat(int64_t number, UnicodeString& toInsertInto, int32_t pos) const | 685 NFRule::doFormat(int64_t number, UnicodeString& toInsertInto, int32_t pos, UErro
rCode& status) const |
| 648 { | 686 { |
| 649 // first, insert the rule's rule text into toInsertInto at the | 687 // first, insert the rule's rule text into toInsertInto at the |
| 650 // specified position, then insert the results of the substitutions | 688 // specified position, then insert the results of the substitutions |
| 651 // into the right places in toInsertInto (notice we do the | 689 // into the right places in toInsertInto (notice we do the |
| 652 // substitutions in reverse order so that the offsets don't get | 690 // substitutions in reverse order so that the offsets don't get |
| 653 // messed up) | 691 // messed up) |
| 654 toInsertInto.insert(pos, ruleText); | 692 int32_t pluralRuleStart = ruleText.length(); |
| 655 sub2->doSubstitution(number, toInsertInto, pos); | 693 int32_t lengthOffset = 0; |
| 656 sub1->doSubstitution(number, toInsertInto, pos); | 694 if (!rulePatternFormat) { |
| 695 toInsertInto.insert(pos, ruleText); |
| 696 } |
| 697 else { |
| 698 pluralRuleStart = ruleText.indexOf(gDollarOpenParenthesis, -1, 0); |
| 699 int pluralRuleEnd = ruleText.indexOf(gClosedParenthesisDollar, -1, plura
lRuleStart); |
| 700 int initialLength = toInsertInto.length(); |
| 701 if (pluralRuleEnd < ruleText.length() - 1) { |
| 702 toInsertInto.insert(pos, ruleText.tempSubString(pluralRuleEnd + 2)); |
| 703 } |
| 704 toInsertInto.insert(pos, |
| 705 rulePatternFormat->format((int32_t)(number/uprv_pow(radix, exponent)
), status)); |
| 706 if (pluralRuleStart > 0) { |
| 707 toInsertInto.insert(pos, ruleText.tempSubString(0, pluralRuleStart))
; |
| 708 } |
| 709 lengthOffset = ruleText.length() - (toInsertInto.length() - initialLengt
h); |
| 710 } |
| 711 |
| 712 if (!sub2->isNullSubstitution()) { |
| 713 sub2->doSubstitution(number, toInsertInto, pos - (sub2->getPos() > plura
lRuleStart ? lengthOffset : 0), status); |
| 714 } |
| 715 if (!sub1->isNullSubstitution()) { |
| 716 sub1->doSubstitution(number, toInsertInto, pos - (sub1->getPos() > plura
lRuleStart ? lengthOffset : 0), status); |
| 717 } |
| 657 } | 718 } |
| 658 | 719 |
| 659 /** | 720 /** |
| 660 * Formats the number, and inserts the resulting text into | 721 * Formats the number, and inserts the resulting text into |
| 661 * toInsertInto. | 722 * toInsertInto. |
| 662 * @param number The number being formatted | 723 * @param number The number being formatted |
| 663 * @param toInsertInto The string where the resultant text should | 724 * @param toInsertInto The string where the resultant text should |
| 664 * be inserted | 725 * be inserted |
| 665 * @param pos The position in toInsertInto where the resultant text | 726 * @param pos The position in toInsertInto where the resultant text |
| 666 * should be inserted | 727 * should be inserted |
| 667 */ | 728 */ |
| 668 void | 729 void |
| 669 NFRule::doFormat(double number, UnicodeString& toInsertInto, int32_t pos) const | 730 NFRule::doFormat(double number, UnicodeString& toInsertInto, int32_t pos, UError
Code& status) const |
| 670 { | 731 { |
| 671 // first, insert the rule's rule text into toInsertInto at the | 732 // first, insert the rule's rule text into toInsertInto at the |
| 672 // specified position, then insert the results of the substitutions | 733 // specified position, then insert the results of the substitutions |
| 673 // into the right places in toInsertInto | 734 // into the right places in toInsertInto |
| 674 // [again, we have two copies of this routine that do the same thing | 735 // [again, we have two copies of this routine that do the same thing |
| 675 // so that we don't sacrifice precision in a long by casting it | 736 // so that we don't sacrifice precision in a long by casting it |
| 676 // to a double] | 737 // to a double] |
| 677 toInsertInto.insert(pos, ruleText); | 738 int32_t pluralRuleStart = ruleText.length(); |
| 678 sub2->doSubstitution(number, toInsertInto, pos); | 739 int32_t lengthOffset = 0; |
| 679 sub1->doSubstitution(number, toInsertInto, pos); | 740 if (!rulePatternFormat) { |
| 741 toInsertInto.insert(pos, ruleText); |
| 742 } |
| 743 else { |
| 744 pluralRuleStart = ruleText.indexOf(gDollarOpenParenthesis, -1, 0); |
| 745 int pluralRuleEnd = ruleText.indexOf(gClosedParenthesisDollar, -1, plura
lRuleStart); |
| 746 int initialLength = toInsertInto.length(); |
| 747 if (pluralRuleEnd < ruleText.length() - 1) { |
| 748 toInsertInto.insert(pos, ruleText.tempSubString(pluralRuleEnd + 2)); |
| 749 } |
| 750 toInsertInto.insert(pos, |
| 751 rulePatternFormat->format((int32_t)(number/uprv_pow(radix, exponent)
), status)); |
| 752 if (pluralRuleStart > 0) { |
| 753 toInsertInto.insert(pos, ruleText.tempSubString(0, pluralRuleStart))
; |
| 754 } |
| 755 lengthOffset = ruleText.length() - (toInsertInto.length() - initialLengt
h); |
| 756 } |
| 757 |
| 758 if (!sub2->isNullSubstitution()) { |
| 759 sub2->doSubstitution(number, toInsertInto, pos - (sub2->getPos() > plura
lRuleStart ? lengthOffset : 0), status); |
| 760 } |
| 761 if (!sub1->isNullSubstitution()) { |
| 762 sub1->doSubstitution(number, toInsertInto, pos - (sub1->getPos() > plura
lRuleStart ? lengthOffset : 0), status); |
| 763 } |
| 680 } | 764 } |
| 681 | 765 |
| 682 /** | 766 /** |
| 683 * Used by the owning rule set to determine whether to invoke the | 767 * Used by the owning rule set to determine whether to invoke the |
| 684 * rollback rule (i.e., whether this rule or the one that precedes | 768 * rollback rule (i.e., whether this rule or the one that precedes |
| 685 * it in the rule set's list should be used to format the number) | 769 * it in the rule set's list should be used to format the number) |
| 686 * @param The number being formatted | 770 * @param The number being formatted |
| 687 * @return True if the rule set should use the rule that precedes | 771 * @return True if the rule set should use the rule that precedes |
| 688 * this one in its list; false if it should use this rule | 772 * this one in its list; false if it should use this rule |
| 689 */ | 773 */ |
| (...skipping 439 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1129 #if !UCONFIG_NO_COLLATION | 1213 #if !UCONFIG_NO_COLLATION |
| 1130 // go through all this grief if we're in lenient-parse mode | 1214 // go through all this grief if we're in lenient-parse mode |
| 1131 if (formatter->isLenient()) { | 1215 if (formatter->isLenient()) { |
| 1132 // get the formatter's collator and use it to create two | 1216 // get the formatter's collator and use it to create two |
| 1133 // collation element iterators, one over the target string | 1217 // collation element iterators, one over the target string |
| 1134 // and another over the prefix (right now, we'll throw an | 1218 // and another over the prefix (right now, we'll throw an |
| 1135 // exception if the collator we get back from the formatter | 1219 // exception if the collator we get back from the formatter |
| 1136 // isn't a RuleBasedCollator, because RuleBasedCollator defines | 1220 // isn't a RuleBasedCollator, because RuleBasedCollator defines |
| 1137 // the CollationElementIterator protocol. Hopefully, this | 1221 // the CollationElementIterator protocol. Hopefully, this |
| 1138 // will change someday.) | 1222 // will change someday.) |
| 1139 RuleBasedCollator* collator = (RuleBasedCollator*)formatter->getCollator
(); | 1223 const RuleBasedCollator* collator = formatter->getCollator(); |
| 1140 CollationElementIterator* strIter = collator->createCollationElementIter
ator(str); | 1224 if (collator == NULL) { |
| 1141 CollationElementIterator* prefixIter = collator->createCollationElementI
terator(prefix); | 1225 status = U_MEMORY_ALLOCATION_ERROR; |
| 1226 return 0; |
| 1227 } |
| 1228 LocalPointer<CollationElementIterator> strIter(collator->createCollation
ElementIterator(str)); |
| 1229 LocalPointer<CollationElementIterator> prefixIter(collator->createCollat
ionElementIterator(prefix)); |
| 1142 // Check for memory allocation error. | 1230 // Check for memory allocation error. |
| 1143 if (collator == NULL || strIter == NULL || prefixIter == NULL) { | 1231 if (strIter.isNull() || prefixIter.isNull()) { |
| 1144 » delete collator; | 1232 status = U_MEMORY_ALLOCATION_ERROR; |
| 1145 » delete strIter; | 1233 return 0; |
| 1146 » delete prefixIter; | |
| 1147 » status = U_MEMORY_ALLOCATION_ERROR; | |
| 1148 » return 0; | |
| 1149 } | 1234 } |
| 1150 | 1235 |
| 1151 UErrorCode err = U_ZERO_ERROR; | 1236 UErrorCode err = U_ZERO_ERROR; |
| 1152 | 1237 |
| 1153 // The original code was problematic. Consider this match: | 1238 // The original code was problematic. Consider this match: |
| 1154 // prefix = "fifty-" | 1239 // prefix = "fifty-" |
| 1155 // string = " fifty-7" | 1240 // string = " fifty-7" |
| 1156 // The intent is to match string up to the '7', by matching 'fifty-' at
position 1 | 1241 // The intent is to match string up to the '7', by matching 'fifty-' at
position 1 |
| 1157 // in the string. Unfortunately, we were getting a match, and then comp
uting where | 1242 // in the string. Unfortunately, we were getting a match, and then comp
uting where |
| 1158 // the match terminated by rematching the string. The rematch code was
using as an | 1243 // the match terminated by rematching the string. The rematch code was
using as an |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1190 | 1275 |
| 1191 // if skipping over ignorables brought to the end of | 1276 // if skipping over ignorables brought to the end of |
| 1192 // the prefix, we DID match: drop out of the loop | 1277 // the prefix, we DID match: drop out of the loop |
| 1193 if (oPrefix == CollationElementIterator::NULLORDER) { | 1278 if (oPrefix == CollationElementIterator::NULLORDER) { |
| 1194 break; | 1279 break; |
| 1195 } | 1280 } |
| 1196 | 1281 |
| 1197 // if skipping over ignorables brought us to the end | 1282 // if skipping over ignorables brought us to the end |
| 1198 // of the target string, we didn't match and return 0 | 1283 // of the target string, we didn't match and return 0 |
| 1199 if (oStr == CollationElementIterator::NULLORDER) { | 1284 if (oStr == CollationElementIterator::NULLORDER) { |
| 1200 delete prefixIter; | |
| 1201 delete strIter; | |
| 1202 return 0; | 1285 return 0; |
| 1203 } | 1286 } |
| 1204 | 1287 |
| 1205 // match collation elements from the two strings | 1288 // match collation elements from the two strings |
| 1206 // (considering only primary differences). If we | 1289 // (considering only primary differences). If we |
| 1207 // get a mismatch, dump out and return 0 | 1290 // get a mismatch, dump out and return 0 |
| 1208 if (CollationElementIterator::primaryOrder(oStr) | 1291 if (CollationElementIterator::primaryOrder(oStr) |
| 1209 != CollationElementIterator::primaryOrder(oPrefix)) { | 1292 != CollationElementIterator::primaryOrder(oPrefix)) { |
| 1210 delete prefixIter; | |
| 1211 delete strIter; | |
| 1212 return 0; | 1293 return 0; |
| 1213 | 1294 |
| 1214 // otherwise, advance to the next character in each string | 1295 // otherwise, advance to the next character in each string |
| 1215 // and loop (we drop out of the loop when we exhaust | 1296 // and loop (we drop out of the loop when we exhaust |
| 1216 // collation elements in the prefix) | 1297 // collation elements in the prefix) |
| 1217 } else { | 1298 } else { |
| 1218 oStr = strIter->next(err); | 1299 oStr = strIter->next(err); |
| 1219 oPrefix = prefixIter->next(err); | 1300 oPrefix = prefixIter->next(err); |
| 1220 } | 1301 } |
| 1221 } | 1302 } |
| 1222 | 1303 |
| 1223 int32_t result = strIter->getOffset(); | 1304 int32_t result = strIter->getOffset(); |
| 1224 if (oStr != CollationElementIterator::NULLORDER) { | 1305 if (oStr != CollationElementIterator::NULLORDER) { |
| 1225 --result; // back over character that we don't want to consume; | 1306 --result; // back over character that we don't want to consume; |
| 1226 } | 1307 } |
| 1227 | 1308 |
| 1228 #ifdef RBNF_DEBUG | 1309 #ifdef RBNF_DEBUG |
| 1229 fprintf(stderr, "prefix length: %d\n", result); | 1310 fprintf(stderr, "prefix length: %d\n", result); |
| 1230 #endif | 1311 #endif |
| 1231 delete prefixIter; | |
| 1232 delete strIter; | |
| 1233 | |
| 1234 return result; | 1312 return result; |
| 1235 #if 0 | 1313 #if 0 |
| 1236 //---------------------------------------------------------------- | 1314 //---------------------------------------------------------------- |
| 1237 // JDK 1.2-specific API call | 1315 // JDK 1.2-specific API call |
| 1238 // return strIter.getOffset(); | 1316 // return strIter.getOffset(); |
| 1239 //---------------------------------------------------------------- | 1317 //---------------------------------------------------------------- |
| 1240 // JDK 1.1 HACK (take out for 1.2-specific code) | 1318 // JDK 1.1 HACK (take out for 1.2-specific code) |
| 1241 | 1319 |
| 1242 // if we make it to here, we have a successful match. Now we | 1320 // if we make it to here, we have a successful match. Now we |
| 1243 // have to find out HOW MANY characters from the target string | 1321 // have to find out HOW MANY characters from the target string |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1307 * of the match, or -1 if there was no match. Element 1 is the | 1385 * of the match, or -1 if there was no match. Element 1 is the |
| 1308 * number of characters in "str" that matched (which isn't necessarily | 1386 * number of characters in "str" that matched (which isn't necessarily |
| 1309 * the same as the length of "key") | 1387 * the same as the length of "key") |
| 1310 */ | 1388 */ |
| 1311 int32_t | 1389 int32_t |
| 1312 NFRule::findText(const UnicodeString& str, | 1390 NFRule::findText(const UnicodeString& str, |
| 1313 const UnicodeString& key, | 1391 const UnicodeString& key, |
| 1314 int32_t startingAt, | 1392 int32_t startingAt, |
| 1315 int32_t* length) const | 1393 int32_t* length) const |
| 1316 { | 1394 { |
| 1317 #if !UCONFIG_NO_COLLATION | 1395 if (rulePatternFormat) { |
| 1318 // if lenient parsing is turned off, this is easy: just call | 1396 Formattable result; |
| 1319 // String.indexOf() and we're done | 1397 FieldPosition position(UNUM_INTEGER_FIELD); |
| 1398 position.setBeginIndex(startingAt); |
| 1399 rulePatternFormat->parseType(str, this, result, position); |
| 1400 int start = position.getBeginIndex(); |
| 1401 if (start >= 0) { |
| 1402 int32_t pluralRuleStart = ruleText.indexOf(gDollarOpenParenthesis, -
1, 0); |
| 1403 int32_t pluralRuleSuffix = ruleText.indexOf(gClosedParenthesisDollar
, -1, pluralRuleStart) + 2; |
| 1404 int32_t matchLen = position.getEndIndex() - start; |
| 1405 UnicodeString prefix(ruleText.tempSubString(0, pluralRuleStart)); |
| 1406 UnicodeString suffix(ruleText.tempSubString(pluralRuleSuffix)); |
| 1407 if (str.compare(start - prefix.length(), prefix.length(), prefix, 0,
prefix.length()) == 0 |
| 1408 && str.compare(start + matchLen, suffix.length(), suffix, 0,
suffix.length()) == 0) |
| 1409 { |
| 1410 *length = matchLen + prefix.length() + suffix.length(); |
| 1411 return start - prefix.length(); |
| 1412 } |
| 1413 } |
| 1414 *length = 0; |
| 1415 return -1; |
| 1416 } |
| 1320 if (!formatter->isLenient()) { | 1417 if (!formatter->isLenient()) { |
| 1418 // if lenient parsing is turned off, this is easy: just call |
| 1419 // String.indexOf() and we're done |
| 1321 *length = key.length(); | 1420 *length = key.length(); |
| 1322 return str.indexOf(key, startingAt); | 1421 return str.indexOf(key, startingAt); |
| 1323 | 1422 } |
| 1423 else { |
| 1324 // but if lenient parsing is turned ON, we've got some work | 1424 // but if lenient parsing is turned ON, we've got some work |
| 1325 // ahead of us | 1425 // ahead of us |
| 1326 } else | 1426 return findTextLenient(str, key, startingAt, length); |
| 1327 #endif | |
| 1328 { | |
| 1329 //---------------------------------------------------------------- | |
| 1330 // JDK 1.1 HACK (take out of 1.2-specific code) | |
| 1331 | |
| 1332 // in JDK 1.2, CollationElementIterator provides us with an | |
| 1333 // API to map between character offsets and collation elements | |
| 1334 // and we can do this by marching through the string comparing | |
| 1335 // collation elements. We can't do that in JDK 1.1. Insted, | |
| 1336 // we have to go through this horrible slow mess: | |
| 1337 int32_t p = startingAt; | |
| 1338 int32_t keyLen = 0; | |
| 1339 | |
| 1340 // basically just isolate smaller and smaller substrings of | |
| 1341 // the target string (each running to the end of the string, | |
| 1342 // and with the first one running from startingAt to the end) | |
| 1343 // and then use prefixLength() to see if the search key is at | |
| 1344 // the beginning of each substring. This is excruciatingly | |
| 1345 // slow, but it will locate the key and tell use how long the | |
| 1346 // matching text was. | |
| 1347 UnicodeString temp; | |
| 1348 UErrorCode status = U_ZERO_ERROR; | |
| 1349 while (p < str.length() && keyLen == 0) { | |
| 1350 temp.setTo(str, p, str.length() - p); | |
| 1351 keyLen = prefixLength(temp, key, status); | |
| 1352 if (U_FAILURE(status)) { | |
| 1353 » break; | |
| 1354 } | |
| 1355 if (keyLen != 0) { | |
| 1356 *length = keyLen; | |
| 1357 return p; | |
| 1358 } | |
| 1359 ++p; | |
| 1360 } | |
| 1361 // if we make it to here, we didn't find it. Return -1 for the | |
| 1362 // location. The length should be ignored, but set it to 0, | |
| 1363 // which should be "safe" | |
| 1364 *length = 0; | |
| 1365 return -1; | |
| 1366 | |
| 1367 //---------------------------------------------------------------- | |
| 1368 // JDK 1.2 version of this routine | |
| 1369 //RuleBasedCollator collator = (RuleBasedCollator)formatter.getCollator(
); | |
| 1370 // | |
| 1371 //CollationElementIterator strIter = collator.getCollationElementIterato
r(str); | |
| 1372 //CollationElementIterator keyIter = collator.getCollationElementIterato
r(key); | |
| 1373 // | |
| 1374 //int keyStart = -1; | |
| 1375 // | |
| 1376 //str.setOffset(startingAt); | |
| 1377 // | |
| 1378 //int oStr = strIter.next(); | |
| 1379 //int oKey = keyIter.next(); | |
| 1380 //while (oKey != CollationElementIterator.NULLORDER) { | |
| 1381 // while (oStr != CollationElementIterator.NULLORDER && | |
| 1382 // CollationElementIterator.primaryOrder(oStr) == 0) | |
| 1383 // oStr = strIter.next(); | |
| 1384 // | |
| 1385 // while (oKey != CollationElementIterator.NULLORDER && | |
| 1386 // CollationElementIterator.primaryOrder(oKey) == 0) | |
| 1387 // oKey = keyIter.next(); | |
| 1388 // | |
| 1389 // if (oStr == CollationElementIterator.NULLORDER) { | |
| 1390 // return new int[] { -1, 0 }; | |
| 1391 // } | |
| 1392 // | |
| 1393 // if (oKey == CollationElementIterator.NULLORDER) { | |
| 1394 // break; | |
| 1395 // } | |
| 1396 // | |
| 1397 // if (CollationElementIterator.primaryOrder(oStr) == | |
| 1398 // CollationElementIterator.primaryOrder(oKey)) { | |
| 1399 // keyStart = strIter.getOffset(); | |
| 1400 // oStr = strIter.next(); | |
| 1401 // oKey = keyIter.next(); | |
| 1402 // } else { | |
| 1403 // if (keyStart != -1) { | |
| 1404 // keyStart = -1; | |
| 1405 // keyIter.reset(); | |
| 1406 // } else { | |
| 1407 // oStr = strIter.next(); | |
| 1408 // } | |
| 1409 // } | |
| 1410 //} | |
| 1411 // | |
| 1412 //if (oKey == CollationElementIterator.NULLORDER) { | |
| 1413 // return new int[] { keyStart, strIter.getOffset() - keyStart }; | |
| 1414 //} else { | |
| 1415 // return new int[] { -1, 0 }; | |
| 1416 //} | |
| 1417 } | 1427 } |
| 1418 } | 1428 } |
| 1419 | 1429 |
| 1430 int32_t |
| 1431 NFRule::findTextLenient(const UnicodeString& str, |
| 1432 const UnicodeString& key, |
| 1433 int32_t startingAt, |
| 1434 int32_t* length) const |
| 1435 { |
| 1436 //---------------------------------------------------------------- |
| 1437 // JDK 1.1 HACK (take out of 1.2-specific code) |
| 1438 |
| 1439 // in JDK 1.2, CollationElementIterator provides us with an |
| 1440 // API to map between character offsets and collation elements |
| 1441 // and we can do this by marching through the string comparing |
| 1442 // collation elements. We can't do that in JDK 1.1. Insted, |
| 1443 // we have to go through this horrible slow mess: |
| 1444 int32_t p = startingAt; |
| 1445 int32_t keyLen = 0; |
| 1446 |
| 1447 // basically just isolate smaller and smaller substrings of |
| 1448 // the target string (each running to the end of the string, |
| 1449 // and with the first one running from startingAt to the end) |
| 1450 // and then use prefixLength() to see if the search key is at |
| 1451 // the beginning of each substring. This is excruciatingly |
| 1452 // slow, but it will locate the key and tell use how long the |
| 1453 // matching text was. |
| 1454 UnicodeString temp; |
| 1455 UErrorCode status = U_ZERO_ERROR; |
| 1456 while (p < str.length() && keyLen == 0) { |
| 1457 temp.setTo(str, p, str.length() - p); |
| 1458 keyLen = prefixLength(temp, key, status); |
| 1459 if (U_FAILURE(status)) { |
| 1460 break; |
| 1461 } |
| 1462 if (keyLen != 0) { |
| 1463 *length = keyLen; |
| 1464 return p; |
| 1465 } |
| 1466 ++p; |
| 1467 } |
| 1468 // if we make it to here, we didn't find it. Return -1 for the |
| 1469 // location. The length should be ignored, but set it to 0, |
| 1470 // which should be "safe" |
| 1471 *length = 0; |
| 1472 return -1; |
| 1473 } |
| 1474 |
| 1420 /** | 1475 /** |
| 1421 * Checks to see whether a string consists entirely of ignorable | 1476 * Checks to see whether a string consists entirely of ignorable |
| 1422 * characters. | 1477 * characters. |
| 1423 * @param str The string to test. | 1478 * @param str The string to test. |
| 1424 * @return true if the string is empty of consists entirely of | 1479 * @return true if the string is empty of consists entirely of |
| 1425 * characters that the number formatter's collator says are | 1480 * characters that the number formatter's collator says are |
| 1426 * ignorable at the primary-order level. false otherwise. | 1481 * ignorable at the primary-order level. false otherwise. |
| 1427 */ | 1482 */ |
| 1428 UBool | 1483 UBool |
| 1429 NFRule::allIgnorable(const UnicodeString& str, UErrorCode& status) const | 1484 NFRule::allIgnorable(const UnicodeString& str, UErrorCode& status) const |
| 1430 { | 1485 { |
| 1431 // if the string is empty, we can just return true | 1486 // if the string is empty, we can just return true |
| 1432 if (str.length() == 0) { | 1487 if (str.length() == 0) { |
| 1433 return TRUE; | 1488 return TRUE; |
| 1434 } | 1489 } |
| 1435 | 1490 |
| 1436 #if !UCONFIG_NO_COLLATION | 1491 #if !UCONFIG_NO_COLLATION |
| 1437 // if lenient parsing is turned on, walk through the string with | 1492 // if lenient parsing is turned on, walk through the string with |
| 1438 // a collation element iterator and make sure each collation | 1493 // a collation element iterator and make sure each collation |
| 1439 // element is 0 (ignorable) at the primary level | 1494 // element is 0 (ignorable) at the primary level |
| 1440 if (formatter->isLenient()) { | 1495 if (formatter->isLenient()) { |
| 1441 RuleBasedCollator* collator = (RuleBasedCollator*)(formatter->getCollato
r()); | 1496 const RuleBasedCollator* collator = formatter->getCollator(); |
| 1442 CollationElementIterator* iter = collator->createCollationElementIterato
r(str); | 1497 if (collator == NULL) { |
| 1443 | 1498 status = U_MEMORY_ALLOCATION_ERROR; |
| 1499 return FALSE; |
| 1500 } |
| 1501 LocalPointer<CollationElementIterator> iter(collator->createCollationEle
mentIterator(str)); |
| 1502 |
| 1444 // Memory allocation error check. | 1503 // Memory allocation error check. |
| 1445 if (collator == NULL || iter == NULL) { | 1504 if (iter.isNull()) { |
| 1446 » delete collator; | 1505 status = U_MEMORY_ALLOCATION_ERROR; |
| 1447 » delete iter; | 1506 return FALSE; |
| 1448 » status = U_MEMORY_ALLOCATION_ERROR; | |
| 1449 » return FALSE; | |
| 1450 } | 1507 } |
| 1451 | 1508 |
| 1452 UErrorCode err = U_ZERO_ERROR; | 1509 UErrorCode err = U_ZERO_ERROR; |
| 1453 int32_t o = iter->next(err); | 1510 int32_t o = iter->next(err); |
| 1454 while (o != CollationElementIterator::NULLORDER | 1511 while (o != CollationElementIterator::NULLORDER |
| 1455 && CollationElementIterator::primaryOrder(o) == 0) { | 1512 && CollationElementIterator::primaryOrder(o) == 0) { |
| 1456 o = iter->next(err); | 1513 o = iter->next(err); |
| 1457 } | 1514 } |
| 1458 | 1515 |
| 1459 delete iter; | |
| 1460 return o == CollationElementIterator::NULLORDER; | 1516 return o == CollationElementIterator::NULLORDER; |
| 1461 } | 1517 } |
| 1462 #endif | 1518 #endif |
| 1463 | 1519 |
| 1464 // if lenient parsing is turned off, there is no such thing as | 1520 // if lenient parsing is turned off, there is no such thing as |
| 1465 // an ignorable character: return true only if the string is empty | 1521 // an ignorable character: return true only if the string is empty |
| 1466 return FALSE; | 1522 return FALSE; |
| 1467 } | 1523 } |
| 1468 | 1524 |
| 1469 U_NAMESPACE_END | 1525 U_NAMESPACE_END |
| 1470 | 1526 |
| 1471 /* U_HAVE_RBNF */ | 1527 /* U_HAVE_RBNF */ |
| 1472 #endif | 1528 #endif |
| 1473 | |
| 1474 | |
| OLD | NEW |