1 /* 2 ****************************************************************************** 3 * Copyright (C) 1997-2012, International Business Machines 4 * Corporation and others. All Rights Reserved. 5 ****************************************************************************** 6 * file name: nfsubs.cpp 7 * encoding: US-ASCII 8 * tab size: 8 (not used) 9 * indentation:4 10 * 11 * Modification history 12 * Date Name Comments 13 * 10/11/2001 Doug Ported from ICU4J 14 */ 15 16 #include <stdio.h> 17 #include "utypeinfo.h" // for 'typeid' to work 18 19 #include "nfsubs.h" 20 #include "digitlst.h" 21 22 #if U_HAVE_RBNF 23 24 static const UChar gLessThan = 0x003c; 25 static const UChar gEquals = 0x003d; 26 static const UChar gGreaterThan = 0x003e; 27 static const UChar gPercent = 0x0025; 28 static const UChar gPound = 0x0023; 29 static const UChar gZero = 0x0030; 30 static const UChar gSpace = 0x0020; 31 32 static const UChar gEqualsEquals[] = 33 { 34 0x3D, 0x3D, 0 35 }; /* "==" */ 36 static const UChar gGreaterGreaterGreaterThan[] = 37 { 38 0x3E, 0x3E, 0x3E, 0 39 }; /* ">>>" */ 40 static const UChar gGreaterGreaterThan[] = 41 { 42 0x3E, 0x3E, 0 43 }; /* ">>" */ 44 45 U_NAMESPACE_BEGIN 46 47 class SameValueSubstitution : public NFSubstitution { 48 public: 49 SameValueSubstitution(int32_t pos, 50 const NFRuleSet* ruleset, 51 const RuleBasedNumberFormat* formatter, 52 const UnicodeString& description, 53 UErrorCode& status); 54 virtual ~SameValueSubstitution(); 55 56 virtual int64_t transformNumber(int64_t number) const { return number; } 57 virtual double transformNumber(double number) const { return number; } 58 virtual double composeRuleValue(double newRuleValue, double /*oldRuleValue*/) const { return newRuleValue; } 59 virtual double calcUpperBound(double oldUpperBound) const { return oldUpperBound; } 60 virtual UChar tokenChar() const { return (UChar)0x003d; } // '=' 61 62 public: 63 static UClassID getStaticClassID(void); 64 virtual UClassID getDynamicClassID(void) const; 65 }; 66 67 SameValueSubstitution::~SameValueSubstitution() {} 68 69 class MultiplierSubstitution : public NFSubstitution { 70 double divisor; 71 int64_t ldivisor; 72 73 public: 74 MultiplierSubstitution(int32_t _pos, 75 double _divisor, 76 const NFRuleSet* _ruleSet, 77 const RuleBasedNumberFormat* formatter, 78 const UnicodeString& description, 79 UErrorCode& status) 80 : NFSubstitution(_pos, _ruleSet, formatter, description, status), divisor(_divisor) 81 { 82 ldivisor = util64_fromDouble(divisor); 83 if (divisor == 0) { 84 status = U_PARSE_ERROR; 85 } 86 } 87 virtual ~MultiplierSubstitution(); 88 89 virtual void setDivisor(int32_t radix, int32_t exponent, UErrorCode& status) { 90 divisor = uprv_pow(radix, exponent); 91 ldivisor = util64_fromDouble(divisor); 92 93 if(divisor == 0) { 94 status = U_PARSE_ERROR; 95 } 96 } 97 98 virtual UBool operator==(const NFSubstitution& rhs) const; 99 100 virtual int64_t transformNumber(int64_t number) const { 101 return number / ldivisor; 102 } 103 104 virtual double transformNumber(double number) const { 105 if (getRuleSet()) { 106 return uprv_floor(number / divisor); 107 } else { 108 return number/divisor; 109 } 110 } 111 112 virtual double composeRuleValue(double newRuleValue, double /*oldRuleValue*/) const { 113 return newRuleValue * divisor; 114 } 115 116 virtual double calcUpperBound(double /*oldUpperBound*/) const { return divisor; } 117 118 virtual UChar tokenChar() const { return (UChar)0x003c; } // '<' 119 120 public: 121 static UClassID getStaticClassID(void); 122 virtual UClassID getDynamicClassID(void) const; 123 }; 124 125 MultiplierSubstitution::~MultiplierSubstitution() {} 126 127 class ModulusSubstitution : public NFSubstitution { 128 double divisor; 129 int64_t ldivisor; 130 const NFRule* ruleToUse; 131 public: 132 ModulusSubstitution(int32_t pos, 133 double _divisor, 134 const NFRule* rulePredecessor, 135 const NFRuleSet* ruleSet, 136 const RuleBasedNumberFormat* formatter, 137 const UnicodeString& description, 138 UErrorCode& status); 139 virtual ~ModulusSubstitution(); 140 141 virtual void setDivisor(int32_t radix, int32_t exponent, UErrorCode& status) { 142 divisor = uprv_pow(radix, exponent); 143 ldivisor = util64_fromDouble(divisor); 144 145 if (divisor == 0) { 146 status = U_PARSE_ERROR; 147 } 148 } 149 150 virtual UBool operator==(const NFSubstitution& rhs) const; 151 152 virtual void doSubstitution(int64_t number, UnicodeString& toInsertInto, int32_t pos) const; 153 virtual void doSubstitution(double number, UnicodeString& toInsertInto, int32_t pos) const; 154 155 virtual int64_t transformNumber(int64_t number) const { return number % ldivisor; } 156 virtual double transformNumber(double number) const { return uprv_fmod(number, divisor); } 157 158 virtual UBool doParse(const UnicodeString& text, 159 ParsePosition& parsePosition, 160 double baseValue, 161 double upperBound, 162 UBool lenientParse, 163 Formattable& result) const; 164 165 virtual double composeRuleValue(double newRuleValue, double oldRuleValue) const { 166 return oldRuleValue - uprv_fmod(oldRuleValue, divisor) + newRuleValue; 167 } 168 169 virtual double calcUpperBound(double /*oldUpperBound*/) const { return divisor; } 170 171 virtual UBool isModulusSubstitution() const { return TRUE; } 172 173 virtual UChar tokenChar() const { return (UChar)0x003e; } // '>' 174 175 virtual void toString(UnicodeString& result) const; 176 177 public: 178 static UClassID getStaticClassID(void); 179 virtual UClassID getDynamicClassID(void) const; 180 }; 181 182 ModulusSubstitution::~ModulusSubstitution() {} 183 184 class IntegralPartSubstitution : public NFSubstitution { 185 public: 186 IntegralPartSubstitution(int32_t _pos, 187 const NFRuleSet* _ruleSet, 188 const RuleBasedNumberFormat* formatter, 189 const UnicodeString& description, 190 UErrorCode& status) 191 : NFSubstitution(_pos, _ruleSet, formatter, description, status) {} 192 virtual ~IntegralPartSubstitution(); 193 194 virtual int64_t transformNumber(int64_t number) const { return number; } 195 virtual double transformNumber(double number) const { return uprv_floor(number); } 196 virtual double composeRuleValue(double newRuleValue, double oldRuleValue) const { return newRuleValue + oldRuleValue; } 197 virtual double calcUpperBound(double /*oldUpperBound*/) const { return DBL_MAX; } 198 virtual UChar tokenChar() const { return (UChar)0x003c; } // '<' 199 200 public: 201 static UClassID getStaticClassID(void); 202 virtual UClassID getDynamicClassID(void) const; 203 }; 204 205 IntegralPartSubstitution::~IntegralPartSubstitution() {} 206 207 class FractionalPartSubstitution : public NFSubstitution { 208 UBool byDigits; 209 UBool useSpaces; 210 enum { kMaxDecimalDigits = 8 }; 211 public: 212 FractionalPartSubstitution(int32_t pos, 213 const NFRuleSet* ruleSet, 214 const RuleBasedNumberFormat* formatter, 215 const UnicodeString& description, 216 UErrorCode& status); 217 virtual ~FractionalPartSubstitution(); 218 219 virtual UBool operator==(const NFSubstitution& rhs) const; 220 221 virtual void doSubstitution(double number, UnicodeString& toInsertInto, int32_t pos) const; 222 virtual void doSubstitution(int64_t /*number*/, UnicodeString& /*toInsertInto*/, int32_t /*_pos*/) const {} 223 virtual int64_t transformNumber(int64_t /*number*/) const { return 0; } 224 virtual double transformNumber(double number) const { return number - uprv_floor(number); } 225 226 virtual UBool doParse(const UnicodeString& text, 227 ParsePosition& parsePosition, 228 double baseValue, 229 double upperBound, 230 UBool lenientParse, 231 Formattable& result) const; 232 233 virtual double composeRuleValue(double newRuleValue, double oldRuleValue) const { return newRuleValue + oldRuleValue; } 234 virtual double calcUpperBound(double /*oldUpperBound*/) const { return 0.0; } 235 virtual UChar tokenChar() const { return (UChar)0x003e; } // '>' 236 237 public: 238 static UClassID getStaticClassID(void); 239 virtual UClassID getDynamicClassID(void) const; 240 }; 241 242 FractionalPartSubstitution::~FractionalPartSubstitution() {} 243 244 class AbsoluteValueSubstitution : public NFSubstitution { 245 public: 246 AbsoluteValueSubstitution(int32_t _pos, 247 const NFRuleSet* _ruleSet, 248 const RuleBasedNumberFormat* formatter, 249 const UnicodeString& description, 250 UErrorCode& status) 251 : NFSubstitution(_pos, _ruleSet, formatter, description, status) {} 252 virtual ~AbsoluteValueSubstitution(); 253 254 virtual int64_t transformNumber(int64_t number) const { return number >= 0 ? number : -number; } 255 virtual double transformNumber(double number) const { return uprv_fabs(number); } 256 virtual double composeRuleValue(double newRuleValue, double /*oldRuleValue*/) const { return -newRuleValue; } 257 virtual double calcUpperBound(double /*oldUpperBound*/) const { return DBL_MAX; } 258 virtual UChar tokenChar() const { return (UChar)0x003e; } // '>' 259 260 public: 261 static UClassID getStaticClassID(void); 262 virtual UClassID getDynamicClassID(void) const; 263 }; 264 265 AbsoluteValueSubstitution::~AbsoluteValueSubstitution() {} 266 267 class NumeratorSubstitution : public NFSubstitution { 268 double denominator; 269 int64_t ldenominator; 270 UBool withZeros; 271 public: 272 static inline UnicodeString fixdesc(const UnicodeString& desc) { 273 if (desc.endsWith(LTLT, 2)) { 274 UnicodeString result(desc, 0, desc.length()-1); 275 return result; 276 } 277 return desc; 278 } 279 NumeratorSubstitution(int32_t _pos, 280 double _denominator, 281 const NFRuleSet* _ruleSet, 282 const RuleBasedNumberFormat* formatter, 283 const UnicodeString& description, 284 UErrorCode& status) 285 : NFSubstitution(_pos, _ruleSet, formatter, fixdesc(description), status), denominator(_denominator) 286 { 287 ldenominator = util64_fromDouble(denominator); 288 withZeros = description.endsWith(LTLT, 2); 289 } 290 virtual ~NumeratorSubstitution(); 291 292 virtual UBool operator==(const NFSubstitution& rhs) const; 293 294 virtual int64_t transformNumber(int64_t number) const { return number * ldenominator; } 295 virtual double transformNumber(double number) const { return uprv_round(number * denominator); } 296 297 virtual void doSubstitution(int64_t /*number*/, UnicodeString& /*toInsertInto*/, int32_t /*_pos*/) const {} 298 virtual void doSubstitution(double number, UnicodeString& toInsertInto, int32_t pos) const; 299 virtual UBool doParse(const UnicodeString& text, 300 ParsePosition& parsePosition, 301 double baseValue, 302 double upperBound, 303 UBool /*lenientParse*/, 304 Formattable& result) const; 305 306 virtual double composeRuleValue(double newRuleValue, double oldRuleValue) const { return newRuleValue / oldRuleValue; } 307 virtual double calcUpperBound(double /*oldUpperBound*/) const { return denominator; } 308 virtual UChar tokenChar() const { return (UChar)0x003c; } // '<' 309 private: 310 static const UChar LTLT[2]; 311 312 public: 313 static UClassID getStaticClassID(void); 314 virtual UClassID getDynamicClassID(void) const; 315 }; 316 317 NumeratorSubstitution::~NumeratorSubstitution() {} 318 319 class NullSubstitution : public NFSubstitution { 320 public: 321 NullSubstitution(int32_t _pos, 322 const NFRuleSet* _ruleSet, 323 const RuleBasedNumberFormat* formatter, 324 const UnicodeString& description, 325 UErrorCode& status) 326 : NFSubstitution(_pos, _ruleSet, formatter, description, status) {} 327 virtual ~NullSubstitution(); 328 329 virtual void toString(UnicodeString& /*result*/) const {} 330 virtual void doSubstitution(double /*number*/, UnicodeString& /*toInsertInto*/, int32_t /*_pos*/) const {} 331 virtual void doSubstitution(int64_t /*number*/, UnicodeString& /*toInsertInto*/, int32_t /*_pos*/) const {} 332 virtual int64_t transformNumber(int64_t /*number*/) const { return 0; } 333 virtual double transformNumber(double /*number*/) const { return 0; } 334 virtual UBool doParse(const UnicodeString& /*text*/, 335 ParsePosition& /*parsePosition*/, 336 double baseValue, 337 double /*upperBound*/, 338 UBool /*lenientParse*/, 339 Formattable& result) const 340 { result.setDouble(baseValue); return TRUE; } 341 virtual double composeRuleValue(double /*newRuleValue*/, double /*oldRuleValue*/) const { return 0.0; } // never called 342 virtual double calcUpperBound(double /*oldUpperBound*/) const { return 0; } // never called 343 virtual UBool isNullSubstitution() const { return TRUE; } 344 virtual UChar tokenChar() const { return (UChar)0x0020; } // ' ' never called 345 346 public: 347 static UClassID getStaticClassID(void); 348 virtual UClassID getDynamicClassID(void) const; 349 }; 350 351 NullSubstitution::~NullSubstitution() {} 352 353 NFSubstitution* 354 NFSubstitution::makeSubstitution(int32_t pos, 355 const NFRule* rule, 356 const NFRule* predecessor, 357 const NFRuleSet* ruleSet, 358 const RuleBasedNumberFormat* formatter, 359 const UnicodeString& description, 360 UErrorCode& status) 361 { 362 // if the description is empty, return a NullSubstitution 363 if (description.length() == 0) { 364 return new NullSubstitution(pos, ruleSet, formatter, description, status); 365 } 366 367 switch (description.charAt(0)) { 368 // if the description begins with '<'... 369 case gLessThan: 370 // throw an exception if the rule is a negative number 371 // rule 372 if (rule->getBaseValue() == NFRule::kNegativeNumberRule) { 373 // throw new IllegalArgumentException("<< not allowed in negative-number rule"); 374 status = U_PARSE_ERROR; 375 return NULL; 376 } 377 378 // if the rule is a fraction rule, return an 379 // IntegralPartSubstitution 380 else if (rule->getBaseValue() == NFRule::kImproperFractionRule 381 || rule->getBaseValue() == NFRule::kProperFractionRule 382 || rule->getBaseValue() == NFRule::kMasterRule) { 383 return new IntegralPartSubstitution(pos, ruleSet, formatter, description, status); 384 } 385 386 // if the rule set containing the rule is a fraction 387 // rule set, return a NumeratorSubstitution 388 else if (ruleSet->isFractionRuleSet()) { 389 return new NumeratorSubstitution(pos, (double)rule->getBaseValue(), 390 formatter->getDefaultRuleSet(), formatter, description, status); 391 } 392 393 // otherwise, return a MultiplierSubstitution 394 else { 395 return new MultiplierSubstitution(pos, rule->getDivisor(), ruleSet, 396 formatter, description, status); 397 } 398 399 // if the description begins with '>'... 400 case gGreaterThan: 401 // if the rule is a negative-number rule, return 402 // an AbsoluteValueSubstitution 403 if (rule->getBaseValue() == NFRule::kNegativeNumberRule) { 404 return new AbsoluteValueSubstitution(pos, ruleSet, formatter, description, status); 405 } 406 407 // if the rule is a fraction rule, return a 408 // FractionalPartSubstitution 409 else if (rule->getBaseValue() == NFRule::kImproperFractionRule 410 || rule->getBaseValue() == NFRule::kProperFractionRule 411 || rule->getBaseValue() == NFRule::kMasterRule) { 412 return new FractionalPartSubstitution(pos, ruleSet, formatter, description, status); 413 } 414 415 // if the rule set owning the rule is a fraction rule set, 416 // throw an exception 417 else if (ruleSet->isFractionRuleSet()) { 418 // throw new IllegalArgumentException(">> not allowed in fraction rule set"); 419 status = U_PARSE_ERROR; 420 return NULL; 421 } 422 423 // otherwise, return a ModulusSubstitution 424 else { 425 return new ModulusSubstitution(pos, rule->getDivisor(), predecessor, 426 ruleSet, formatter, description, status); 427 } 428 429 // if the description begins with '=', always return a 430 // SameValueSubstitution 431 case gEquals: 432 return new SameValueSubstitution(pos, ruleSet, formatter, description, status); 433 434 // and if it's anything else, throw an exception 435 default: 436 // throw new IllegalArgumentException("Illegal substitution character"); 437 status = U_PARSE_ERROR; 438 } 439 return NULL; 440 } 441 442 NFSubstitution::NFSubstitution(int32_t _pos, 443 const NFRuleSet* _ruleSet, 444 const RuleBasedNumberFormat* formatter, 445 const UnicodeString& description, 446 UErrorCode& status) 447 : pos(_pos), ruleSet(NULL), numberFormat(NULL) 448 { 449 // the description should begin and end with the same character. 450 // If it doesn't that's a syntax error. Otherwise, 451 // makeSubstitution() was the only thing that needed to know 452 // about these characters, so strip them off 453 UnicodeString workingDescription(description); 454 if (description.length() >= 2 455 && description.charAt(0) == description.charAt(description.length() - 1)) 456 { 457 workingDescription.remove(description.length() - 1, 1); 458 workingDescription.remove(0, 1); 459 } 460 else if (description.length() != 0) { 461 // throw new IllegalArgumentException("Illegal substitution syntax"); 462 status = U_PARSE_ERROR; 463 return; 464 } 465 466 // if the description was just two paired token characters 467 // (i.e., "<<" or ">>"), it uses the rule set it belongs to to 468 // format its result 469 if (workingDescription.length() == 0) { 470 this->ruleSet = _ruleSet; 471 } 472 // if the description contains a rule set name, that's the rule 473 // set we use to format the result: get a reference to the 474 // names rule set 475 else if (workingDescription.charAt(0) == gPercent) { 476 this->ruleSet = formatter->findRuleSet(workingDescription, status); 477 } 478 // if the description begins with 0 or #, treat it as a 479 // DecimalFormat pattern, and initialize a DecimalFormat with 480 // that pattern (then set it to use the DecimalFormatSymbols 481 // belonging to our formatter) 482 else if (workingDescription.charAt(0) == gPound || workingDescription.charAt(0) ==gZero) { 483 DecimalFormatSymbols* sym = formatter->getDecimalFormatSymbols(); 484 if (!sym) { 485 status = U_MISSING_RESOURCE_ERROR; 486 return; 487 } 488 this->numberFormat = new DecimalFormat(workingDescription, *sym, status); 489 /* test for NULL */ 490 if (this->numberFormat == 0) { 491 status = U_MEMORY_ALLOCATION_ERROR; 492 return; 493 } 494 if (U_FAILURE(status)) { 495 delete (DecimalFormat*)this->numberFormat; 496 this->numberFormat = NULL; 497 return; 498 } 499 // this->numberFormat->setDecimalFormatSymbols(formatter->getDecimalFormatSymbols()); 500 } 501 // if the description is ">>>", this substitution bypasses the 502 // usual rule-search process and always uses the rule that precedes 503 // it in its own rule set's rule list (this is used for place-value 504 // notations: formats where you want to see a particular part of 505 // a number even when it's 0) 506 else if (workingDescription.charAt(0) == gGreaterThan) { 507 // this causes problems when >>> is used in a frationalPartSubstitution 508 // this->ruleSet = NULL; 509 this->ruleSet = _ruleSet; 510 this->numberFormat = NULL; 511 } 512 // and of the description is none of these things, it's a syntax error 513 else { 514 // throw new IllegalArgumentException("Illegal substitution syntax"); 515 status = U_PARSE_ERROR; 516 } 517 } 518 519 NFSubstitution::~NFSubstitution() 520 { 521 // cast away const 522 delete (NumberFormat*)numberFormat; numberFormat = NULL; 523 } 524 525 /** 526 * Set's the substitution's divisor. Used by NFRule.setBaseValue(). 527 * A no-op for all substitutions except multiplier and modulus 528 * substitutions. 529 * @param radix The radix of the divisor 530 * @param exponent The exponent of the divisor 531 */ 532 void 533 NFSubstitution::setDivisor(int32_t /*radix*/, int32_t /*exponent*/, UErrorCode& /*status*/) { 534 // a no-op for all substitutions except multiplier and modulus substitutions 535 } 536 537 538 //----------------------------------------------------------------------- 539 // boilerplate 540 //----------------------------------------------------------------------- 541 542 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NFSubstitution) 543 544 /** 545 * Compares two substitutions for equality 546 * @param The substitution to compare this one to 547 * @return true if the two substitutions are functionally equivalent 548 */ 549 UBool 550 NFSubstitution::operator==(const NFSubstitution& rhs) const 551 { 552 // compare class and all of the fields all substitutions have 553 // in common 554 // this should be called by subclasses before their own equality tests 555 return typeid(*this) == typeid(rhs) 556 && pos == rhs.pos 557 && (ruleSet == NULL) == (rhs.ruleSet == NULL) 558 // && ruleSet == rhs.ruleSet causes circularity, other checks to make instead? 559 && (numberFormat == NULL 560 ? (rhs.numberFormat == NULL) 561 : (*numberFormat == *rhs.numberFormat)); 562 } 563 564 /** 565 * Returns a textual description of the substitution 566 * @return A textual description of the substitution. This might 567 * not be identical to the description it was created from, but 568 * it'll produce the same result. 569 */ 570 void 571 NFSubstitution::toString(UnicodeString& text) const 572 { 573 // use tokenChar() to get the character at the beginning and 574 // end of the substitutin token. In between them will go 575 // either the name of the rule set it uses, or the pattern of 576 // the DecimalFormat it uses 577 text.remove(); 578 text.append(tokenChar()); 579 580 UnicodeString temp; 581 if (ruleSet != NULL) { 582 ruleSet->getName(temp); 583 } else if (numberFormat != NULL) { 584 numberFormat->toPattern(temp); 585 } 586 text.append(temp); 587 text.append(tokenChar()); 588 } 589 590 //----------------------------------------------------------------------- 591 // formatting 592 //----------------------------------------------------------------------- 593 594 /** 595 * Performs a mathematical operation on the number, formats it using 596 * either ruleSet or decimalFormat, and inserts the result into 597 * toInsertInto. 598 * @param number The number being formatted. 599 * @param toInsertInto The string we insert the result into 600 * @param pos The position in toInsertInto where the owning rule's 601 * rule text begins (this value is added to this substitution's 602 * position to determine exactly where to insert the new text) 603 */ 604 void 605 NFSubstitution::doSubstitution(int64_t number, UnicodeString& toInsertInto, int32_t _pos) const 606 { 607 if (ruleSet != NULL) { 608 // perform a transformation on the number that is dependent 609 // on the type of substitution this is, then just call its 610 // rule set's format() method to format the result 611 ruleSet->format(transformNumber(number), toInsertInto, _pos + this->pos); 612 } else if (numberFormat != NULL) { 613 // or perform the transformation on the number (preserving 614 // the result's fractional part if the formatter it set 615 // to show it), then use that formatter's format() method 616 // to format the result 617 double numberToFormat = transformNumber((double)number); 618 if (numberFormat->getMaximumFractionDigits() == 0) { 619 numberToFormat = uprv_floor(numberToFormat); 620 } 621 622 UnicodeString temp; 623 numberFormat->format(numberToFormat, temp); 624 toInsertInto.insert(_pos + this->pos, temp); 625 } 626 } 627 628 /** 629 * Performs a mathematical operation on the number, formats it using 630 * either ruleSet or decimalFormat, and inserts the result into 631 * toInsertInto. 632 * @param number The number being formatted. 633 * @param toInsertInto The string we insert the result into 634 * @param pos The position in toInsertInto where the owning rule's 635 * rule text begins (this value is added to this substitution's 636 * position to determine exactly where to insert the new text) 637 */ 638 void 639 NFSubstitution::doSubstitution(double number, UnicodeString& toInsertInto, int32_t _pos) const { 640 // perform a transformation on the number being formatted that 641 // is dependent on the type of substitution this is 642 double numberToFormat = transformNumber(number); 643 644 // if the result is an integer, from here on out we work in integer 645 // space (saving time and memory and preserving accuracy) 646 if (numberToFormat == uprv_floor(numberToFormat) && ruleSet != NULL) { 647 ruleSet->format(util64_fromDouble(numberToFormat), toInsertInto, _pos + this->pos); 648 649 // if the result isn't an integer, then call either our rule set's 650 // format() method or our DecimalFormat's format() method to 651 // format the result 652 } else { 653 if (ruleSet != NULL) { 654 ruleSet->format(numberToFormat, toInsertInto, _pos + this->pos); 655 } else if (numberFormat != NULL) { 656 UnicodeString temp; 657 numberFormat->format(numberToFormat, temp); 658 toInsertInto.insert(_pos + this->pos, temp); 659 } 660 } 661 } 662 663 664 //----------------------------------------------------------------------- 665 // parsing 666 //----------------------------------------------------------------------- 667 668 #ifdef RBNF_DEBUG 669 #include <stdio.h> 670 #endif 671 672 /** 673 * Parses a string using the rule set or DecimalFormat belonging 674 * to this substitution. If there's a match, a mathematical 675 * operation (the inverse of the one used in formatting) is 676 * performed on the result of the parse and the value passed in 677 * and returned as the result. The parse position is updated to 678 * point to the first unmatched character in the string. 679 * @param text The string to parse 680 * @param parsePosition On entry, ignored, but assumed to be 0. 681 * On exit, this is updated to point to the first unmatched 682 * character (or 0 if the substitution didn't match) 683 * @param baseValue A partial parse result that should be 684 * combined with the result of this parse 685 * @param upperBound When searching the rule set for a rule 686 * matching the string passed in, only rules with base values 687 * lower than this are considered 688 * @param lenientParse If true and matching against rules fails, 689 * the substitution will also try matching the text against 690 * numerals using a default-costructed NumberFormat. If false, 691 * no extra work is done. (This value is false whenever the 692 * formatter isn't in lenient-parse mode, but is also false 693 * under some conditions even when the formatter _is_ in 694 * lenient-parse mode.) 695 * @return If there's a match, this is the result of composing 696 * baseValue with whatever was returned from matching the 697 * characters. This will be either a Long or a Double. If there's 698 * no match this is new Long(0) (not null), and parsePosition 699 * is left unchanged. 700 */ 701 UBool 702 NFSubstitution::doParse(const UnicodeString& text, 703 ParsePosition& parsePosition, 704 double baseValue, 705 double upperBound, 706 UBool lenientParse, 707 Formattable& result) const 708 { 709 #ifdef RBNF_DEBUG 710 fprintf(stderr, "<nfsubs> %x bv: %g ub: %g\n", this, baseValue, upperBound); 711 #endif 712 // figure out the highest base value a rule can have and match 713 // the text being parsed (this varies according to the type of 714 // substitutions: multiplier, modulus, and numerator substitutions 715 // restrict the search to rules with base values lower than their 716 // own; same-value substitutions leave the upper bound wherever 717 // it was, and the others allow any rule to match 718 upperBound = calcUpperBound(upperBound); 719 720 // use our rule set to parse the text. If that fails and 721 // lenient parsing is enabled (this is always false if the 722 // formatter's lenient-parsing mode is off, but it may also 723 // be false even when the formatter's lenient-parse mode is 724 // on), then also try parsing the text using a default- 725 // constructed NumberFormat 726 if (ruleSet != NULL) { 727 ruleSet->parse(text, parsePosition, upperBound, result); 728 if (lenientParse && !ruleSet->isFractionRuleSet() && parsePosition.getIndex() == 0) { 729 UErrorCode status = U_ZERO_ERROR; 730 NumberFormat* fmt = NumberFormat::createInstance(status); 731 if (U_SUCCESS(status)) { 732 fmt->parse(text, result, parsePosition); 733 } 734 delete fmt; 735 } 736 737 // ...or use our DecimalFormat to parse the text 738 } else if (numberFormat != NULL) { 739 numberFormat->parse(text, result, parsePosition); 740 } 741 742 // if the parse was successful, we've already advanced the caller's 743 // parse position (this is the one function that doesn't have one 744 // of its own). Derive a parse result and return it as a Long, 745 // if possible, or a Double 746 if (parsePosition.getIndex() != 0) { 747 UErrorCode status = U_ZERO_ERROR; 748 double tempResult = result.getDouble(status); 749 750 // composeRuleValue() produces a full parse result from 751 // the partial parse result passed to this function from 752 // the caller (this is either the owning rule's base value 753 // or the partial result obtained from composing the 754 // owning rule's base value with its other substitution's 755 // parse result) and the partial parse result obtained by 756 // matching the substitution (which will be the same value 757 // the caller would get by parsing just this part of the 758 // text with RuleBasedNumberFormat.parse() ). How the two 759 // values are used to derive the full parse result depends 760 // on the types of substitutions: For a regular rule, the 761 // ultimate result is its multiplier substitution's result 762 // times the rule's divisor (or the rule's base value) plus 763 // the modulus substitution's result (which will actually 764 // supersede part of the rule's base value). For a negative- 765 // number rule, the result is the negative of its substitution's 766 // result. For a fraction rule, it's the sum of its two 767 // substitution results. For a rule in a fraction rule set, 768 // it's the numerator substitution's result divided by 769 // the rule's base value. Results from same-value substitutions 770 // propagate back upard, and null substitutions don't affect 771 // the result. 772 tempResult = composeRuleValue(tempResult, baseValue); 773 result.setDouble(tempResult); 774 return TRUE; 775 // if the parse was UNsuccessful, return 0 776 } else { 777 result.setLong(0); 778 return FALSE; 779 } 780 } 781 782 UBool 783 NFSubstitution::isNullSubstitution() const { 784 return FALSE; 785 } 786 787 /** 788 * Returns true if this is a modulus substitution. (We didn't do this 789 * with instanceof partially because it causes source files to 790 * proliferate and partially because we have to port this to C++.) 791 * @return true if this object is an instance of ModulusSubstitution 792 */ 793 UBool 794 NFSubstitution::isModulusSubstitution() const { 795 return FALSE; 796 } 797 798 //=================================================================== 799 // SameValueSubstitution 800 //=================================================================== 801 802 /** 803 * A substitution that passes the value passed to it through unchanged. 804 * Represented by == in rule descriptions. 805 */ 806 SameValueSubstitution::SameValueSubstitution(int32_t _pos, 807 const NFRuleSet* _ruleSet, 808 const RuleBasedNumberFormat* formatter, 809 const UnicodeString& description, 810 UErrorCode& status) 811 : NFSubstitution(_pos, _ruleSet, formatter, description, status) 812 { 813 if (0 == description.compare(gEqualsEquals, 2)) { 814 // throw new IllegalArgumentException("== is not a legal token"); 815 status = U_PARSE_ERROR; 816 } 817 } 818 819 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SameValueSubstitution) 820 821 //=================================================================== 822 // MultiplierSubstitution 823 //=================================================================== 824 825 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MultiplierSubstitution) 826 827 UBool MultiplierSubstitution::operator==(const NFSubstitution& rhs) const 828 { 829 return NFSubstitution::operator==(rhs) && 830 divisor == ((const MultiplierSubstitution*)&rhs)->divisor; 831 } 832 833 834 //=================================================================== 835 // ModulusSubstitution 836 //=================================================================== 837 838 /** 839 * A substitution that divides the number being formatted by the its rule's 840 * divisor and formats the remainder. Represented by ">>" in a 841 * regular rule. 842 */ 843 ModulusSubstitution::ModulusSubstitution(int32_t _pos, 844 double _divisor, 845 const NFRule* predecessor, 846 const NFRuleSet* _ruleSet, 847 const RuleBasedNumberFormat* formatter, 848 const UnicodeString& description, 849 UErrorCode& status) 850 : NFSubstitution(_pos, _ruleSet, formatter, description, status) 851 , divisor(_divisor) 852 , ruleToUse(NULL) 853 { 854 ldivisor = util64_fromDouble(_divisor); 855 856 // the owning rule's divisor controls the behavior of this 857 // substitution: rather than keeping a backpointer to the rule, 858 // we keep a copy of the divisor 859 860 if (ldivisor == 0) { 861 status = U_PARSE_ERROR; 862 } 863 864 if (0 == description.compare(gGreaterGreaterGreaterThan, 3)) { 865 // the >>> token doesn't alter how this substituion calculates the 866 // values it uses for formatting and parsing, but it changes 867 // what's done with that value after it's obtained: >>> short- 868 // circuits the rule-search process and goes straight to the 869 // specified rule to format the substitution value 870 ruleToUse = predecessor; 871 } 872 } 873 874 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ModulusSubstitution) 875 876 UBool ModulusSubstitution::operator==(const NFSubstitution& rhs) const 877 { 878 return NFSubstitution::operator==(rhs) && 879 divisor == ((const ModulusSubstitution*)&rhs)->divisor && 880 ruleToUse == ((const ModulusSubstitution*)&rhs)->ruleToUse; 881 } 882 883 //----------------------------------------------------------------------- 884 // formatting 885 //----------------------------------------------------------------------- 886 887 888 /** 889 * If this is a >>> substitution, use ruleToUse to fill in 890 * the substitution. Otherwise, just use the superclass function. 891 * @param number The number being formatted 892 * @toInsertInto The string to insert the result of this substitution 893 * into 894 * @param pos The position of the rule text in toInsertInto 895 */ 896 void 897 ModulusSubstitution::doSubstitution(int64_t number, UnicodeString& toInsertInto, int32_t _pos) const 898 { 899 // if this isn't a >>> substitution, just use the inherited version 900 // of this function (which uses either a rule set or a DecimalFormat 901 // to format its substitution value) 902 if (ruleToUse == NULL) { 903 NFSubstitution::doSubstitution(number, toInsertInto, _pos); 904 905 // a >>> substitution goes straight to a particular rule to 906 // format the substitution value 907 } else { 908 int64_t numberToFormat = transformNumber(number); 909 ruleToUse->doFormat(numberToFormat, toInsertInto, _pos + getPos()); 910 } 911 } 912 913 /** 914 * If this is a >>> substitution, use ruleToUse to fill in 915 * the substitution. Otherwise, just use the superclass function. 916 * @param number The number being formatted 917 * @toInsertInto The string to insert the result of this substitution 918 * into 919 * @param pos The position of the rule text in toInsertInto 920 */ 921 void 922 ModulusSubstitution::doSubstitution(double number, UnicodeString& toInsertInto, int32_t _pos) const 923 { 924 // if this isn't a >>> substitution, just use the inherited version 925 // of this function (which uses either a rule set or a DecimalFormat 926 // to format its substitution value) 927 if (ruleToUse == NULL) { 928 NFSubstitution::doSubstitution(number, toInsertInto, _pos); 929 930 // a >>> substitution goes straight to a particular rule to 931 // format the substitution value 932 } else { 933 double numberToFormat = transformNumber(number); 934 935 ruleToUse->doFormat(numberToFormat, toInsertInto, _pos + getPos()); 936 } 937 } 938 939 //----------------------------------------------------------------------- 940 // parsing 941 //----------------------------------------------------------------------- 942 943 /** 944 * If this is a >>> substitution, match only against ruleToUse. 945 * Otherwise, use the superclass function. 946 * @param text The string to parse 947 * @param parsePosition Ignored on entry, updated on exit to point to 948 * the first unmatched character. 949 * @param baseValue The partial parse result prior to calling this 950 * routine. 951 */ 952 UBool 953 ModulusSubstitution::doParse(const UnicodeString& text, 954 ParsePosition& parsePosition, 955 double baseValue, 956 double upperBound, 957 UBool lenientParse, 958 Formattable& result) const 959 { 960 // if this isn't a >>> substitution, we can just use the 961 // inherited parse() routine to do the parsing 962 if (ruleToUse == NULL) { 963 return NFSubstitution::doParse(text, parsePosition, baseValue, upperBound, lenientParse, result); 964 965 // but if it IS a >>> substitution, we have to do it here: we 966 // use the specific rule's doParse() method, and then we have to 967 // do some of the other work of NFRuleSet.parse() 968 } else { 969 ruleToUse->doParse(text, parsePosition, FALSE, upperBound, result); 970 971 if (parsePosition.getIndex() != 0) { 972 UErrorCode status = U_ZERO_ERROR; 973 double tempResult = result.getDouble(status); 974 tempResult = composeRuleValue(tempResult, baseValue); 975 result.setDouble(tempResult); 976 } 977 978 return TRUE; 979 } 980 } 981 /** 982 * Returns a textual description of the substitution 983 * @return A textual description of the substitution. This might 984 * not be identical to the description it was created from, but 985 * it'll produce the same result. 986 */ 987 void 988 ModulusSubstitution::toString(UnicodeString& text) const 989 { 990 // use tokenChar() to get the character at the beginning and 991 // end of the substitutin token. In between them will go 992 // either the name of the rule set it uses, or the pattern of 993 // the DecimalFormat it uses 994 995 if ( ruleToUse != NULL ) { // Must have been a >>> substitution. 996 text.remove(); 997 text.append(tokenChar()); 998 text.append(tokenChar()); 999 text.append(tokenChar()); 1000 } else { // Otherwise just use the super-class function. 1001 NFSubstitution::toString(text); 1002 } 1003 } 1004 //=================================================================== 1005 // IntegralPartSubstitution 1006 //=================================================================== 1007 1008 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IntegralPartSubstitution) 1009 1010 1011 //=================================================================== 1012 // FractionalPartSubstitution 1013 //=================================================================== 1014 1015 1016 /** 1017 * Constructs a FractionalPartSubstitution. This object keeps a flag 1018 * telling whether it should format by digits or not. In addition, 1019 * it marks the rule set it calls (if any) as a fraction rule set. 1020 */ 1021 FractionalPartSubstitution::FractionalPartSubstitution(int32_t _pos, 1022 const NFRuleSet* _ruleSet, 1023 const RuleBasedNumberFormat* formatter, 1024 const UnicodeString& description, 1025 UErrorCode& status) 1026 : NFSubstitution(_pos, _ruleSet, formatter, description, status) 1027 , byDigits(FALSE) 1028 , useSpaces(TRUE) 1029 1030 { 1031 // akk, ruleSet can change in superclass constructor 1032 if (0 == description.compare(gGreaterGreaterThan, 2) || 1033 0 == description.compare(gGreaterGreaterGreaterThan, 3) || 1034 _ruleSet == getRuleSet()) { 1035 byDigits = TRUE; 1036 if (0 == description.compare(gGreaterGreaterGreaterThan, 3)) { 1037 useSpaces = FALSE; 1038 } 1039 } else { 1040 // cast away const 1041 ((NFRuleSet*)getRuleSet())->makeIntoFractionRuleSet(); 1042 } 1043 } 1044 1045 //----------------------------------------------------------------------- 1046 // formatting 1047 //----------------------------------------------------------------------- 1048 1049 /** 1050 * If in "by digits" mode, fills in the substitution one decimal digit 1051 * at a time using the rule set containing this substitution. 1052 * Otherwise, uses the superclass function. 1053 * @param number The number being formatted 1054 * @param toInsertInto The string to insert the result of formatting 1055 * the substitution into 1056 * @param pos The position of the owning rule's rule text in 1057 * toInsertInto 1058 */ 1059 void 1060 FractionalPartSubstitution::doSubstitution(double number, UnicodeString& toInsertInto, int32_t _pos) const 1061 { 1062 // if we're not in "byDigits" mode, just use the inherited 1063 // doSubstitution() routine 1064 if (!byDigits) { 1065 NFSubstitution::doSubstitution(number, toInsertInto, _pos); 1066 1067 // if we're in "byDigits" mode, transform the value into an integer 1068 // by moving the decimal point eight places to the right and 1069 // pulling digits off the right one at a time, formatting each digit 1070 // as an integer using this substitution's owning rule set 1071 // (this is slower, but more accurate, than doing it from the 1072 // other end) 1073 } else { 1074 // int32_t numberToFormat = (int32_t)uprv_round(transformNumber(number) * uprv_pow(10, kMaxDecimalDigits)); 1075 // // this flag keeps us from formatting trailing zeros. It starts 1076 // // out false because we're pulling from the right, and switches 1077 // // to true the first time we encounter a non-zero digit 1078 // UBool doZeros = FALSE; 1079 // for (int32_t i = 0; i < kMaxDecimalDigits; i++) { 1080 // int64_t digit = numberToFormat % 10; 1081 // if (digit != 0 || doZeros) { 1082 // if (doZeros && useSpaces) { 1083 // toInsertInto.insert(_pos + getPos(), gSpace); 1084 // } 1085 // doZeros = TRUE; 1086 // getRuleSet()->format(digit, toInsertInto, _pos + getPos()); 1087 // } 1088 // numberToFormat /= 10; 1089 // } 1090 1091 DigitList dl; 1092 dl.set(number); 1093 dl.roundFixedPoint(20); // round to 20 fraction digits. 1094 dl.reduce(); // Removes any trailing zeros. 1095 1096 UBool pad = FALSE; 1097 for (int32_t didx = dl.getCount()-1; didx>=dl.getDecimalAt(); didx--) { 1098 // Loop iterates over fraction digits, starting with the LSD. 1099 // include both real digits from the number, and zeros 1100 // to the left of the MSD but to the right of the decimal point. 1101 if (pad && useSpaces) { 1102 toInsertInto.insert(_pos + getPos(), gSpace); 1103 } else { 1104 pad = TRUE; 1105 } 1106 int64_t digit = didx>=0 ? dl.getDigit(didx) - '0' : 0; 1107 getRuleSet()->format(digit, toInsertInto, _pos + getPos()); 1108 } 1109 1110 if (!pad) { 1111 // hack around lack of precision in digitlist. if we would end up with 1112 // "foo point" make sure we add a " zero" to the end. 1113 getRuleSet()->format((int64_t)0, toInsertInto, _pos + getPos()); 1114 } 1115 } 1116 } 1117 1118 //----------------------------------------------------------------------- 1119 // parsing 1120 //----------------------------------------------------------------------- 1121 1122 /** 1123 * If in "by digits" mode, parses the string as if it were a string 1124 * of individual digits; otherwise, uses the superclass function. 1125 * @param text The string to parse 1126 * @param parsePosition Ignored on entry, but updated on exit to point 1127 * to the first unmatched character 1128 * @param baseValue The partial parse result prior to entering this 1129 * function 1130 * @param upperBound Only consider rules with base values lower than 1131 * this when filling in the substitution 1132 * @param lenientParse If true, try matching the text as numerals if 1133 * matching as words doesn't work 1134 * @return If the match was successful, the current partial parse 1135 * result; otherwise new Long(0). The result is either a Long or 1136 * a Double. 1137 */ 1138 1139 UBool 1140 FractionalPartSubstitution::doParse(const UnicodeString& text, 1141 ParsePosition& parsePosition, 1142 double baseValue, 1143 double /*upperBound*/, 1144 UBool lenientParse, 1145 Formattable& resVal) const 1146 { 1147 // if we're not in byDigits mode, we can just use the inherited 1148 // doParse() 1149 if (!byDigits) { 1150 return NFSubstitution::doParse(text, parsePosition, baseValue, 0, lenientParse, resVal); 1151 1152 // if we ARE in byDigits mode, parse the text one digit at a time 1153 // using this substitution's owning rule set (we do this by setting 1154 // upperBound to 10 when calling doParse() ) until we reach 1155 // nonmatching text 1156 } else { 1157 UnicodeString workText(text); 1158 ParsePosition workPos(1); 1159 double result = 0; 1160 int32_t digit; 1161 // double p10 = 0.1; 1162 1163 DigitList dl; 1164 NumberFormat* fmt = NULL; 1165 while (workText.length() > 0 && workPos.getIndex() != 0) { 1166 workPos.setIndex(0); 1167 Formattable temp; 1168 getRuleSet()->parse(workText, workPos, 10, temp); 1169 UErrorCode status = U_ZERO_ERROR; 1170 digit = temp.getLong(status); 1171 // digit = temp.getType() == Formattable::kLong ? 1172 // temp.getLong() : 1173 // (int32_t)temp.getDouble(); 1174 1175 if (lenientParse && workPos.getIndex() == 0) { 1176 if (!fmt) { 1177 status = U_ZERO_ERROR; 1178 fmt = NumberFormat::createInstance(status); 1179 if (U_FAILURE(status)) { 1180 delete fmt; 1181 fmt = NULL; 1182 } 1183 } 1184 if (fmt) { 1185 fmt->parse(workText, temp, workPos); 1186 digit = temp.getLong(status); 1187 } 1188 } 1189 1190 if (workPos.getIndex() != 0) { 1191 dl.append((char)('0' + digit)); 1192 // result += digit * p10; 1193 // p10 /= 10; 1194 parsePosition.setIndex(parsePosition.getIndex() + workPos.getIndex()); 1195 workText.removeBetween(0, workPos.getIndex()); 1196 while (workText.length() > 0 && workText.charAt(0) == gSpace) { 1197 workText.removeBetween(0, 1); 1198 parsePosition.setIndex(parsePosition.getIndex() + 1); 1199 } 1200 } 1201 } 1202 delete fmt; 1203 1204 result = dl.getCount() == 0 ? 0 : dl.getDouble(); 1205 result = composeRuleValue(result, baseValue); 1206 resVal.setDouble(result); 1207 return TRUE; 1208 } 1209 } 1210 1211 UBool 1212 FractionalPartSubstitution::operator==(const NFSubstitution& rhs) const 1213 { 1214 return NFSubstitution::operator==(rhs) && 1215 ((const FractionalPartSubstitution*)&rhs)->byDigits == byDigits; 1216 } 1217 1218 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(FractionalPartSubstitution) 1219 1220 1221 //=================================================================== 1222 // AbsoluteValueSubstitution 1223 //=================================================================== 1224 1225 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(AbsoluteValueSubstitution) 1226 1227 //=================================================================== 1228 // NumeratorSubstitution 1229 //=================================================================== 1230 1231 void 1232 NumeratorSubstitution::doSubstitution(double number, UnicodeString& toInsertInto, int32_t apos) const { 1233 // perform a transformation on the number being formatted that 1234 // is dependent on the type of substitution this is 1235 1236 double numberToFormat = transformNumber(number); 1237 int64_t longNF = util64_fromDouble(numberToFormat); 1238 1239 const NFRuleSet* aruleSet = getRuleSet(); 1240 if (withZeros && aruleSet != NULL) { 1241 // if there are leading zeros in the decimal expansion then emit them 1242 int64_t nf =longNF; 1243 int32_t len = toInsertInto.length(); 1244 while ((nf *= 10) < denominator) { 1245 toInsertInto.insert(apos + getPos(), gSpace); 1246 aruleSet->format((int64_t)0, toInsertInto, apos + getPos()); 1247 } 1248 apos += toInsertInto.length() - len; 1249 } 1250 1251 // if the result is an integer, from here on out we work in integer 1252 // space (saving time and memory and preserving accuracy) 1253 if (numberToFormat == longNF && aruleSet != NULL) { 1254 aruleSet->format(longNF, toInsertInto, apos + getPos()); 1255 1256 // if the result isn't an integer, then call either our rule set's 1257 // format() method or our DecimalFormat's format() method to 1258 // format the result 1259 } else { 1260 if (aruleSet != NULL) { 1261 aruleSet->format(numberToFormat, toInsertInto, apos + getPos()); 1262 } else { 1263 UErrorCode status = U_ZERO_ERROR; 1264 UnicodeString temp; 1265 getNumberFormat()->format(numberToFormat, temp, status); 1266 toInsertInto.insert(apos + getPos(), temp); 1267 } 1268 } 1269 } 1270 1271 UBool 1272 NumeratorSubstitution::doParse(const UnicodeString& text, 1273 ParsePosition& parsePosition, 1274 double baseValue, 1275 double upperBound, 1276 UBool /*lenientParse*/, 1277 Formattable& result) const 1278 { 1279 // we don't have to do anything special to do the parsing here, 1280 // but we have to turn lenient parsing off-- if we leave it on, 1281 // it SERIOUSLY messes up the algorithm 1282 1283 // if withZeros is true, we need to count the zeros 1284 // and use that to adjust the parse result 1285 UErrorCode status = U_ZERO_ERROR; 1286 int32_t zeroCount = 0; 1287 UnicodeString workText(text); 1288 1289 if (withZeros) { 1290 ParsePosition workPos(1); 1291 Formattable temp; 1292 1293 while (workText.length() > 0 && workPos.getIndex() != 0) { 1294 workPos.setIndex(0); 1295 getRuleSet()->parse(workText, workPos, 1, temp); // parse zero or nothing at all 1296 if (workPos.getIndex() == 0) { 1297 // we failed, either there were no more zeros, or the number was formatted with digits 1298 // either way, we're done 1299 break; 1300 } 1301 1302 ++zeroCount; 1303 parsePosition.setIndex(parsePosition.getIndex() + workPos.getIndex()); 1304 workText.remove(0, workPos.getIndex()); 1305 while (workText.length() > 0 && workText.charAt(0) == gSpace) { 1306 workText.remove(0, 1); 1307 parsePosition.setIndex(parsePosition.getIndex() + 1); 1308 } 1309 } 1310 1311 workText = text; 1312 workText.remove(0, (int32_t)parsePosition.getIndex()); 1313 parsePosition.setIndex(0); 1314 } 1315 1316 // we've parsed off the zeros, now let's parse the rest from our current position 1317 NFSubstitution::doParse(workText, parsePosition, withZeros ? 1 : baseValue, upperBound, FALSE, result); 1318 1319 if (withZeros) { 1320 // any base value will do in this case. is there a way to 1321 // force this to not bother trying all the base values? 1322 1323 // compute the 'effective' base and prescale the value down 1324 int64_t n = result.getLong(status); // force conversion! 1325 int64_t d = 1; 1326 int32_t pow = 0; 1327 while (d <= n) { 1328 d *= 10; 1329 ++pow; 1330 } 1331 // now add the zeros 1332 while (zeroCount > 0) { 1333 d *= 10; 1334 --zeroCount; 1335 } 1336 // d is now our true denominator 1337 result.setDouble((double)n/(double)d); 1338 } 1339 1340 return TRUE; 1341 } 1342 1343 UBool 1344 NumeratorSubstitution::operator==(const NFSubstitution& rhs) const 1345 { 1346 return NFSubstitution::operator==(rhs) && 1347 denominator == ((const NumeratorSubstitution*)&rhs)->denominator; 1348 } 1349 1350 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NumeratorSubstitution) 1351 1352 const UChar NumeratorSubstitution::LTLT[] = { 0x003c, 0x003c }; 1353 1354 //=================================================================== 1355 // NullSubstitution 1356 //=================================================================== 1357 1358 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NullSubstitution) 1359 1360 U_NAMESPACE_END 1361 1362 /* U_HAVE_RBNF */ 1363 #endif 1364 1365