Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(404)

Side by Side Diff: source/i18n/nfrule.cpp

Issue 845603002: Update ICU to 54.1 step 1 (Closed) Base URL: https://chromium.googlesource.com/chromium/deps/icu.git@master
Patch Set: remove unusued directories Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « source/i18n/nfrule.h ('k') | source/i18n/nfsubs.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « source/i18n/nfrule.h ('k') | source/i18n/nfsubs.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698