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 24static const UChar gLessThan = 0x003c; 25static const UChar gEquals = 0x003d; 26static const UChar gGreaterThan = 0x003e; 27static const UChar gPercent = 0x0025; 28static const UChar gPound = 0x0023; 29static const UChar gZero = 0x0030; 30static const UChar gSpace = 0x0020; 31 32static const UChar gEqualsEquals[] = 33{ 34 0x3D, 0x3D, 0 35}; /* "==" */ 36static const UChar gGreaterGreaterGreaterThan[] = 37{ 38 0x3E, 0x3E, 0x3E, 0 39}; /* ">>>" */ 40static const UChar gGreaterGreaterThan[] = 41{ 42 0x3E, 0x3E, 0 43}; /* ">>" */ 44 45U_NAMESPACE_BEGIN 46 47class SameValueSubstitution : public NFSubstitution { 48public: 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 62public: 63 static UClassID getStaticClassID(void); 64 virtual UClassID getDynamicClassID(void) const; 65}; 66 67SameValueSubstitution::~SameValueSubstitution() {} 68 69class MultiplierSubstitution : public NFSubstitution { 70 double divisor; 71 int64_t ldivisor; 72 73public: 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 120public: 121 static UClassID getStaticClassID(void); 122 virtual UClassID getDynamicClassID(void) const; 123}; 124 125MultiplierSubstitution::~MultiplierSubstitution() {} 126 127class ModulusSubstitution : public NFSubstitution { 128 double divisor; 129 int64_t ldivisor; 130 const NFRule* ruleToUse; 131public: 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 177public: 178 static UClassID getStaticClassID(void); 179 virtual UClassID getDynamicClassID(void) const; 180}; 181 182ModulusSubstitution::~ModulusSubstitution() {} 183 184class IntegralPartSubstitution : public NFSubstitution { 185public: 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 200public: 201 static UClassID getStaticClassID(void); 202 virtual UClassID getDynamicClassID(void) const; 203}; 204 205IntegralPartSubstitution::~IntegralPartSubstitution() {} 206 207class FractionalPartSubstitution : public NFSubstitution { 208 UBool byDigits; 209 UBool useSpaces; 210 enum { kMaxDecimalDigits = 8 }; 211public: 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 237public: 238 static UClassID getStaticClassID(void); 239 virtual UClassID getDynamicClassID(void) const; 240}; 241 242FractionalPartSubstitution::~FractionalPartSubstitution() {} 243 244class AbsoluteValueSubstitution : public NFSubstitution { 245public: 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 260public: 261 static UClassID getStaticClassID(void); 262 virtual UClassID getDynamicClassID(void) const; 263}; 264 265AbsoluteValueSubstitution::~AbsoluteValueSubstitution() {} 266 267class NumeratorSubstitution : public NFSubstitution { 268 double denominator; 269 int64_t ldenominator; 270 UBool withZeros; 271public: 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; } // '<' 309private: 310 static const UChar LTLT[2]; 311 312public: 313 static UClassID getStaticClassID(void); 314 virtual UClassID getDynamicClassID(void) const; 315}; 316 317NumeratorSubstitution::~NumeratorSubstitution() {} 318 319class NullSubstitution : public NFSubstitution { 320public: 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 346public: 347 static UClassID getStaticClassID(void); 348 virtual UClassID getDynamicClassID(void) const; 349}; 350 351NullSubstitution::~NullSubstitution() {} 352 353NFSubstitution* 354NFSubstitution::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 442NFSubstitution::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 519NFSubstitution::~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 */ 532void 533NFSubstitution::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 542UOBJECT_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 */ 549UBool 550NFSubstitution::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 */ 570void 571NFSubstitution::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 */ 604void 605NFSubstitution::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 */ 638void 639NFSubstitution::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 DigitList digits; 644 digits.set(numberToFormat); 645 646 // if the result is an integer, from here on out we work in integer 647 // space (saving time and memory and preserving accuracy) 648 if (numberToFormat == uprv_floor(numberToFormat) && ruleSet != NULL && (!digits.isInfinite())) { 649 ruleSet->format(util64_fromDouble(numberToFormat), toInsertInto, _pos + this->pos); 650 651 // if the result isn't an integer, then call either our rule set's 652 // format() method or our DecimalFormat's format() method to 653 // format the result 654 } else { 655 if (ruleSet != NULL) { 656 ruleSet->format(numberToFormat, toInsertInto, _pos + this->pos); 657 } else if (numberFormat != NULL) { 658 UnicodeString temp; 659 numberFormat->format(numberToFormat, temp); 660 toInsertInto.insert(_pos + this->pos, temp); 661 } 662 } 663} 664 665 666 //----------------------------------------------------------------------- 667 // parsing 668 //----------------------------------------------------------------------- 669 670#ifdef RBNF_DEBUG 671#include <stdio.h> 672#endif 673 674/** 675 * Parses a string using the rule set or DecimalFormat belonging 676 * to this substitution. If there's a match, a mathematical 677 * operation (the inverse of the one used in formatting) is 678 * performed on the result of the parse and the value passed in 679 * and returned as the result. The parse position is updated to 680 * point to the first unmatched character in the string. 681 * @param text The string to parse 682 * @param parsePosition On entry, ignored, but assumed to be 0. 683 * On exit, this is updated to point to the first unmatched 684 * character (or 0 if the substitution didn't match) 685 * @param baseValue A partial parse result that should be 686 * combined with the result of this parse 687 * @param upperBound When searching the rule set for a rule 688 * matching the string passed in, only rules with base values 689 * lower than this are considered 690 * @param lenientParse If true and matching against rules fails, 691 * the substitution will also try matching the text against 692 * numerals using a default-costructed NumberFormat. If false, 693 * no extra work is done. (This value is false whenever the 694 * formatter isn't in lenient-parse mode, but is also false 695 * under some conditions even when the formatter _is_ in 696 * lenient-parse mode.) 697 * @return If there's a match, this is the result of composing 698 * baseValue with whatever was returned from matching the 699 * characters. This will be either a Long or a Double. If there's 700 * no match this is new Long(0) (not null), and parsePosition 701 * is left unchanged. 702 */ 703UBool 704NFSubstitution::doParse(const UnicodeString& text, 705 ParsePosition& parsePosition, 706 double baseValue, 707 double upperBound, 708 UBool lenientParse, 709 Formattable& result) const 710{ 711#ifdef RBNF_DEBUG 712 fprintf(stderr, "<nfsubs> %x bv: %g ub: %g\n", this, baseValue, upperBound); 713#endif 714 // figure out the highest base value a rule can have and match 715 // the text being parsed (this varies according to the type of 716 // substitutions: multiplier, modulus, and numerator substitutions 717 // restrict the search to rules with base values lower than their 718 // own; same-value substitutions leave the upper bound wherever 719 // it was, and the others allow any rule to match 720 upperBound = calcUpperBound(upperBound); 721 722 // use our rule set to parse the text. If that fails and 723 // lenient parsing is enabled (this is always false if the 724 // formatter's lenient-parsing mode is off, but it may also 725 // be false even when the formatter's lenient-parse mode is 726 // on), then also try parsing the text using a default- 727 // constructed NumberFormat 728 if (ruleSet != NULL) { 729 ruleSet->parse(text, parsePosition, upperBound, result); 730 if (lenientParse && !ruleSet->isFractionRuleSet() && parsePosition.getIndex() == 0) { 731 UErrorCode status = U_ZERO_ERROR; 732 NumberFormat* fmt = NumberFormat::createInstance(status); 733 if (U_SUCCESS(status)) { 734 fmt->parse(text, result, parsePosition); 735 } 736 delete fmt; 737 } 738 739 // ...or use our DecimalFormat to parse the text 740 } else if (numberFormat != NULL) { 741 numberFormat->parse(text, result, parsePosition); 742 } 743 744 // if the parse was successful, we've already advanced the caller's 745 // parse position (this is the one function that doesn't have one 746 // of its own). Derive a parse result and return it as a Long, 747 // if possible, or a Double 748 if (parsePosition.getIndex() != 0) { 749 UErrorCode status = U_ZERO_ERROR; 750 double tempResult = result.getDouble(status); 751 752 // composeRuleValue() produces a full parse result from 753 // the partial parse result passed to this function from 754 // the caller (this is either the owning rule's base value 755 // or the partial result obtained from composing the 756 // owning rule's base value with its other substitution's 757 // parse result) and the partial parse result obtained by 758 // matching the substitution (which will be the same value 759 // the caller would get by parsing just this part of the 760 // text with RuleBasedNumberFormat.parse() ). How the two 761 // values are used to derive the full parse result depends 762 // on the types of substitutions: For a regular rule, the 763 // ultimate result is its multiplier substitution's result 764 // times the rule's divisor (or the rule's base value) plus 765 // the modulus substitution's result (which will actually 766 // supersede part of the rule's base value). For a negative- 767 // number rule, the result is the negative of its substitution's 768 // result. For a fraction rule, it's the sum of its two 769 // substitution results. For a rule in a fraction rule set, 770 // it's the numerator substitution's result divided by 771 // the rule's base value. Results from same-value substitutions 772 // propagate back upard, and null substitutions don't affect 773 // the result. 774 tempResult = composeRuleValue(tempResult, baseValue); 775 result.setDouble(tempResult); 776 return TRUE; 777 // if the parse was UNsuccessful, return 0 778 } else { 779 result.setLong(0); 780 return FALSE; 781 } 782} 783 784UBool 785NFSubstitution::isNullSubstitution() const { 786 return FALSE; 787} 788 789 /** 790 * Returns true if this is a modulus substitution. (We didn't do this 791 * with instanceof partially because it causes source files to 792 * proliferate and partially because we have to port this to C++.) 793 * @return true if this object is an instance of ModulusSubstitution 794 */ 795UBool 796NFSubstitution::isModulusSubstitution() const { 797 return FALSE; 798} 799 800 /** 801 * @return true if this is a decimal format-only substitution 802 */ 803UBool 804NFSubstitution::isDecimalFormatSubstitutionOnly() const { 805 return (ruleSet == NULL && getNumberFormat() != NULL); 806} 807 808 /** 809 * @return true if this substitution uses another ruleSet 810 */ 811UBool 812NFSubstitution::isRuleSetSubstitutionOnly() const { 813 return (getNumberFormat() == NULL && ruleSet != NULL); 814} 815 816//=================================================================== 817// SameValueSubstitution 818//=================================================================== 819 820/** 821 * A substitution that passes the value passed to it through unchanged. 822 * Represented by == in rule descriptions. 823 */ 824SameValueSubstitution::SameValueSubstitution(int32_t _pos, 825 const NFRuleSet* _ruleSet, 826 const RuleBasedNumberFormat* formatter, 827 const UnicodeString& description, 828 UErrorCode& status) 829: NFSubstitution(_pos, _ruleSet, formatter, description, status) 830{ 831 if (0 == description.compare(gEqualsEquals, 2)) { 832 // throw new IllegalArgumentException("== is not a legal token"); 833 status = U_PARSE_ERROR; 834 } 835} 836 837UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SameValueSubstitution) 838 839//=================================================================== 840// MultiplierSubstitution 841//=================================================================== 842 843UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MultiplierSubstitution) 844 845UBool MultiplierSubstitution::operator==(const NFSubstitution& rhs) const 846{ 847 return NFSubstitution::operator==(rhs) && 848 divisor == ((const MultiplierSubstitution*)&rhs)->divisor; 849} 850 851 852//=================================================================== 853// ModulusSubstitution 854//=================================================================== 855 856/** 857 * A substitution that divides the number being formatted by the its rule's 858 * divisor and formats the remainder. Represented by ">>" in a 859 * regular rule. 860 */ 861ModulusSubstitution::ModulusSubstitution(int32_t _pos, 862 double _divisor, 863 const NFRule* predecessor, 864 const NFRuleSet* _ruleSet, 865 const RuleBasedNumberFormat* formatter, 866 const UnicodeString& description, 867 UErrorCode& status) 868 : NFSubstitution(_pos, _ruleSet, formatter, description, status) 869 , divisor(_divisor) 870 , ruleToUse(NULL) 871{ 872 ldivisor = util64_fromDouble(_divisor); 873 874 // the owning rule's divisor controls the behavior of this 875 // substitution: rather than keeping a backpointer to the rule, 876 // we keep a copy of the divisor 877 878 if (ldivisor == 0) { 879 status = U_PARSE_ERROR; 880 } 881 882 if (0 == description.compare(gGreaterGreaterGreaterThan, 3)) { 883 // the >>> token doesn't alter how this substituion calculates the 884 // values it uses for formatting and parsing, but it changes 885 // what's done with that value after it's obtained: >>> short- 886 // circuits the rule-search process and goes straight to the 887 // specified rule to format the substitution value 888 ruleToUse = predecessor; 889 } 890} 891 892UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ModulusSubstitution) 893 894UBool ModulusSubstitution::operator==(const NFSubstitution& rhs) const 895{ 896 return NFSubstitution::operator==(rhs) && 897 divisor == ((const ModulusSubstitution*)&rhs)->divisor && 898 ruleToUse == ((const ModulusSubstitution*)&rhs)->ruleToUse; 899} 900 901//----------------------------------------------------------------------- 902// formatting 903//----------------------------------------------------------------------- 904 905 906/** 907 * If this is a >>> substitution, use ruleToUse to fill in 908 * the substitution. Otherwise, just use the superclass function. 909 * @param number The number being formatted 910 * @toInsertInto The string to insert the result of this substitution 911 * into 912 * @param pos The position of the rule text in toInsertInto 913 */ 914void 915ModulusSubstitution::doSubstitution(int64_t number, UnicodeString& toInsertInto, int32_t _pos) const 916{ 917 // if this isn't a >>> substitution, just use the inherited version 918 // of this function (which uses either a rule set or a DecimalFormat 919 // to format its substitution value) 920 if (ruleToUse == NULL) { 921 NFSubstitution::doSubstitution(number, toInsertInto, _pos); 922 923 // a >>> substitution goes straight to a particular rule to 924 // format the substitution value 925 } else { 926 int64_t numberToFormat = transformNumber(number); 927 ruleToUse->doFormat(numberToFormat, toInsertInto, _pos + getPos()); 928 } 929} 930 931/** 932* If this is a >>> substitution, use ruleToUse to fill in 933* the substitution. Otherwise, just use the superclass function. 934* @param number The number being formatted 935* @toInsertInto The string to insert the result of this substitution 936* into 937* @param pos The position of the rule text in toInsertInto 938*/ 939void 940ModulusSubstitution::doSubstitution(double number, UnicodeString& toInsertInto, int32_t _pos) const 941{ 942 // if this isn't a >>> substitution, just use the inherited version 943 // of this function (which uses either a rule set or a DecimalFormat 944 // to format its substitution value) 945 if (ruleToUse == NULL) { 946 NFSubstitution::doSubstitution(number, toInsertInto, _pos); 947 948 // a >>> substitution goes straight to a particular rule to 949 // format the substitution value 950 } else { 951 double numberToFormat = transformNumber(number); 952 953 ruleToUse->doFormat(numberToFormat, toInsertInto, _pos + getPos()); 954 } 955} 956 957//----------------------------------------------------------------------- 958// parsing 959//----------------------------------------------------------------------- 960 961/** 962 * If this is a >>> substitution, match only against ruleToUse. 963 * Otherwise, use the superclass function. 964 * @param text The string to parse 965 * @param parsePosition Ignored on entry, updated on exit to point to 966 * the first unmatched character. 967 * @param baseValue The partial parse result prior to calling this 968 * routine. 969 */ 970UBool 971ModulusSubstitution::doParse(const UnicodeString& text, 972 ParsePosition& parsePosition, 973 double baseValue, 974 double upperBound, 975 UBool lenientParse, 976 Formattable& result) const 977{ 978 // if this isn't a >>> substitution, we can just use the 979 // inherited parse() routine to do the parsing 980 if (ruleToUse == NULL) { 981 return NFSubstitution::doParse(text, parsePosition, baseValue, upperBound, lenientParse, result); 982 983 // but if it IS a >>> substitution, we have to do it here: we 984 // use the specific rule's doParse() method, and then we have to 985 // do some of the other work of NFRuleSet.parse() 986 } else { 987 ruleToUse->doParse(text, parsePosition, FALSE, upperBound, result); 988 989 if (parsePosition.getIndex() != 0) { 990 UErrorCode status = U_ZERO_ERROR; 991 double tempResult = result.getDouble(status); 992 tempResult = composeRuleValue(tempResult, baseValue); 993 result.setDouble(tempResult); 994 } 995 996 return TRUE; 997 } 998} 999/** 1000 * Returns a textual description of the substitution 1001 * @return A textual description of the substitution. This might 1002 * not be identical to the description it was created from, but 1003 * it'll produce the same result. 1004 */ 1005void 1006ModulusSubstitution::toString(UnicodeString& text) const 1007{ 1008 // use tokenChar() to get the character at the beginning and 1009 // end of the substitutin token. In between them will go 1010 // either the name of the rule set it uses, or the pattern of 1011 // the DecimalFormat it uses 1012 1013 if ( ruleToUse != NULL ) { // Must have been a >>> substitution. 1014 text.remove(); 1015 text.append(tokenChar()); 1016 text.append(tokenChar()); 1017 text.append(tokenChar()); 1018 } else { // Otherwise just use the super-class function. 1019 NFSubstitution::toString(text); 1020 } 1021} 1022//=================================================================== 1023// IntegralPartSubstitution 1024//=================================================================== 1025 1026UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IntegralPartSubstitution) 1027 1028 1029//=================================================================== 1030// FractionalPartSubstitution 1031//=================================================================== 1032 1033 1034 /** 1035 * Constructs a FractionalPartSubstitution. This object keeps a flag 1036 * telling whether it should format by digits or not. In addition, 1037 * it marks the rule set it calls (if any) as a fraction rule set. 1038 */ 1039FractionalPartSubstitution::FractionalPartSubstitution(int32_t _pos, 1040 const NFRuleSet* _ruleSet, 1041 const RuleBasedNumberFormat* formatter, 1042 const UnicodeString& description, 1043 UErrorCode& status) 1044 : NFSubstitution(_pos, _ruleSet, formatter, description, status) 1045 , byDigits(FALSE) 1046 , useSpaces(TRUE) 1047 1048{ 1049 // akk, ruleSet can change in superclass constructor 1050 if (0 == description.compare(gGreaterGreaterThan, 2) || 1051 0 == description.compare(gGreaterGreaterGreaterThan, 3) || 1052 _ruleSet == getRuleSet()) { 1053 byDigits = TRUE; 1054 if (0 == description.compare(gGreaterGreaterGreaterThan, 3)) { 1055 useSpaces = FALSE; 1056 } 1057 } else { 1058 // cast away const 1059 ((NFRuleSet*)getRuleSet())->makeIntoFractionRuleSet(); 1060 } 1061} 1062 1063//----------------------------------------------------------------------- 1064// formatting 1065//----------------------------------------------------------------------- 1066 1067/** 1068 * If in "by digits" mode, fills in the substitution one decimal digit 1069 * at a time using the rule set containing this substitution. 1070 * Otherwise, uses the superclass function. 1071 * @param number The number being formatted 1072 * @param toInsertInto The string to insert the result of formatting 1073 * the substitution into 1074 * @param pos The position of the owning rule's rule text in 1075 * toInsertInto 1076 */ 1077void 1078FractionalPartSubstitution::doSubstitution(double number, UnicodeString& toInsertInto, int32_t _pos) const 1079{ 1080 // if we're not in "byDigits" mode, just use the inherited 1081 // doSubstitution() routine 1082 if (!byDigits) { 1083 NFSubstitution::doSubstitution(number, toInsertInto, _pos); 1084 1085 // if we're in "byDigits" mode, transform the value into an integer 1086 // by moving the decimal point eight places to the right and 1087 // pulling digits off the right one at a time, formatting each digit 1088 // as an integer using this substitution's owning rule set 1089 // (this is slower, but more accurate, than doing it from the 1090 // other end) 1091 } else { 1092 // int32_t numberToFormat = (int32_t)uprv_round(transformNumber(number) * uprv_pow(10, kMaxDecimalDigits)); 1093 // // this flag keeps us from formatting trailing zeros. It starts 1094 // // out false because we're pulling from the right, and switches 1095 // // to true the first time we encounter a non-zero digit 1096 // UBool doZeros = FALSE; 1097 // for (int32_t i = 0; i < kMaxDecimalDigits; i++) { 1098 // int64_t digit = numberToFormat % 10; 1099 // if (digit != 0 || doZeros) { 1100 // if (doZeros && useSpaces) { 1101 // toInsertInto.insert(_pos + getPos(), gSpace); 1102 // } 1103 // doZeros = TRUE; 1104 // getRuleSet()->format(digit, toInsertInto, _pos + getPos()); 1105 // } 1106 // numberToFormat /= 10; 1107 // } 1108 1109 DigitList dl; 1110 dl.set(number); 1111 dl.roundFixedPoint(20); // round to 20 fraction digits. 1112 dl.reduce(); // Removes any trailing zeros. 1113 1114 UBool pad = FALSE; 1115 for (int32_t didx = dl.getCount()-1; didx>=dl.getDecimalAt(); didx--) { 1116 // Loop iterates over fraction digits, starting with the LSD. 1117 // include both real digits from the number, and zeros 1118 // to the left of the MSD but to the right of the decimal point. 1119 if (pad && useSpaces) { 1120 toInsertInto.insert(_pos + getPos(), gSpace); 1121 } else { 1122 pad = TRUE; 1123 } 1124 int64_t digit = didx>=0 ? dl.getDigit(didx) - '0' : 0; 1125 getRuleSet()->format(digit, toInsertInto, _pos + getPos()); 1126 } 1127 1128 if (!pad) { 1129 // hack around lack of precision in digitlist. if we would end up with 1130 // "foo point" make sure we add a " zero" to the end. 1131 getRuleSet()->format((int64_t)0, toInsertInto, _pos + getPos()); 1132 } 1133 } 1134} 1135 1136//----------------------------------------------------------------------- 1137// parsing 1138//----------------------------------------------------------------------- 1139 1140/** 1141 * If in "by digits" mode, parses the string as if it were a string 1142 * of individual digits; otherwise, uses the superclass function. 1143 * @param text The string to parse 1144 * @param parsePosition Ignored on entry, but updated on exit to point 1145 * to the first unmatched character 1146 * @param baseValue The partial parse result prior to entering this 1147 * function 1148 * @param upperBound Only consider rules with base values lower than 1149 * this when filling in the substitution 1150 * @param lenientParse If true, try matching the text as numerals if 1151 * matching as words doesn't work 1152 * @return If the match was successful, the current partial parse 1153 * result; otherwise new Long(0). The result is either a Long or 1154 * a Double. 1155 */ 1156 1157UBool 1158FractionalPartSubstitution::doParse(const UnicodeString& text, 1159 ParsePosition& parsePosition, 1160 double baseValue, 1161 double /*upperBound*/, 1162 UBool lenientParse, 1163 Formattable& resVal) const 1164{ 1165 // if we're not in byDigits mode, we can just use the inherited 1166 // doParse() 1167 if (!byDigits) { 1168 return NFSubstitution::doParse(text, parsePosition, baseValue, 0, lenientParse, resVal); 1169 1170 // if we ARE in byDigits mode, parse the text one digit at a time 1171 // using this substitution's owning rule set (we do this by setting 1172 // upperBound to 10 when calling doParse() ) until we reach 1173 // nonmatching text 1174 } else { 1175 UnicodeString workText(text); 1176 ParsePosition workPos(1); 1177 double result = 0; 1178 int32_t digit; 1179// double p10 = 0.1; 1180 1181 DigitList dl; 1182 NumberFormat* fmt = NULL; 1183 while (workText.length() > 0 && workPos.getIndex() != 0) { 1184 workPos.setIndex(0); 1185 Formattable temp; 1186 getRuleSet()->parse(workText, workPos, 10, temp); 1187 UErrorCode status = U_ZERO_ERROR; 1188 digit = temp.getLong(status); 1189// digit = temp.getType() == Formattable::kLong ? 1190// temp.getLong() : 1191// (int32_t)temp.getDouble(); 1192 1193 if (lenientParse && workPos.getIndex() == 0) { 1194 if (!fmt) { 1195 status = U_ZERO_ERROR; 1196 fmt = NumberFormat::createInstance(status); 1197 if (U_FAILURE(status)) { 1198 delete fmt; 1199 fmt = NULL; 1200 } 1201 } 1202 if (fmt) { 1203 fmt->parse(workText, temp, workPos); 1204 digit = temp.getLong(status); 1205 } 1206 } 1207 1208 if (workPos.getIndex() != 0) { 1209 dl.append((char)('0' + digit)); 1210// result += digit * p10; 1211// p10 /= 10; 1212 parsePosition.setIndex(parsePosition.getIndex() + workPos.getIndex()); 1213 workText.removeBetween(0, workPos.getIndex()); 1214 while (workText.length() > 0 && workText.charAt(0) == gSpace) { 1215 workText.removeBetween(0, 1); 1216 parsePosition.setIndex(parsePosition.getIndex() + 1); 1217 } 1218 } 1219 } 1220 delete fmt; 1221 1222 result = dl.getCount() == 0 ? 0 : dl.getDouble(); 1223 result = composeRuleValue(result, baseValue); 1224 resVal.setDouble(result); 1225 return TRUE; 1226 } 1227} 1228 1229UBool 1230FractionalPartSubstitution::operator==(const NFSubstitution& rhs) const 1231{ 1232 return NFSubstitution::operator==(rhs) && 1233 ((const FractionalPartSubstitution*)&rhs)->byDigits == byDigits; 1234} 1235 1236UOBJECT_DEFINE_RTTI_IMPLEMENTATION(FractionalPartSubstitution) 1237 1238 1239//=================================================================== 1240// AbsoluteValueSubstitution 1241//=================================================================== 1242 1243UOBJECT_DEFINE_RTTI_IMPLEMENTATION(AbsoluteValueSubstitution) 1244 1245//=================================================================== 1246// NumeratorSubstitution 1247//=================================================================== 1248 1249void 1250NumeratorSubstitution::doSubstitution(double number, UnicodeString& toInsertInto, int32_t apos) const { 1251 // perform a transformation on the number being formatted that 1252 // is dependent on the type of substitution this is 1253 1254 double numberToFormat = transformNumber(number); 1255 int64_t longNF = util64_fromDouble(numberToFormat); 1256 1257 const NFRuleSet* aruleSet = getRuleSet(); 1258 if (withZeros && aruleSet != NULL) { 1259 // if there are leading zeros in the decimal expansion then emit them 1260 int64_t nf =longNF; 1261 int32_t len = toInsertInto.length(); 1262 while ((nf *= 10) < denominator) { 1263 toInsertInto.insert(apos + getPos(), gSpace); 1264 aruleSet->format((int64_t)0, toInsertInto, apos + getPos()); 1265 } 1266 apos += toInsertInto.length() - len; 1267 } 1268 1269 // if the result is an integer, from here on out we work in integer 1270 // space (saving time and memory and preserving accuracy) 1271 if (numberToFormat == longNF && aruleSet != NULL) { 1272 aruleSet->format(longNF, toInsertInto, apos + getPos()); 1273 1274 // if the result isn't an integer, then call either our rule set's 1275 // format() method or our DecimalFormat's format() method to 1276 // format the result 1277 } else { 1278 if (aruleSet != NULL) { 1279 aruleSet->format(numberToFormat, toInsertInto, apos + getPos()); 1280 } else { 1281 UErrorCode status = U_ZERO_ERROR; 1282 UnicodeString temp; 1283 getNumberFormat()->format(numberToFormat, temp, status); 1284 toInsertInto.insert(apos + getPos(), temp); 1285 } 1286 } 1287} 1288 1289UBool 1290NumeratorSubstitution::doParse(const UnicodeString& text, 1291 ParsePosition& parsePosition, 1292 double baseValue, 1293 double upperBound, 1294 UBool /*lenientParse*/, 1295 Formattable& result) const 1296{ 1297 // we don't have to do anything special to do the parsing here, 1298 // but we have to turn lenient parsing off-- if we leave it on, 1299 // it SERIOUSLY messes up the algorithm 1300 1301 // if withZeros is true, we need to count the zeros 1302 // and use that to adjust the parse result 1303 UErrorCode status = U_ZERO_ERROR; 1304 int32_t zeroCount = 0; 1305 UnicodeString workText(text); 1306 1307 if (withZeros) { 1308 ParsePosition workPos(1); 1309 Formattable temp; 1310 1311 while (workText.length() > 0 && workPos.getIndex() != 0) { 1312 workPos.setIndex(0); 1313 getRuleSet()->parse(workText, workPos, 1, temp); // parse zero or nothing at all 1314 if (workPos.getIndex() == 0) { 1315 // we failed, either there were no more zeros, or the number was formatted with digits 1316 // either way, we're done 1317 break; 1318 } 1319 1320 ++zeroCount; 1321 parsePosition.setIndex(parsePosition.getIndex() + workPos.getIndex()); 1322 workText.remove(0, workPos.getIndex()); 1323 while (workText.length() > 0 && workText.charAt(0) == gSpace) { 1324 workText.remove(0, 1); 1325 parsePosition.setIndex(parsePosition.getIndex() + 1); 1326 } 1327 } 1328 1329 workText = text; 1330 workText.remove(0, (int32_t)parsePosition.getIndex()); 1331 parsePosition.setIndex(0); 1332 } 1333 1334 // we've parsed off the zeros, now let's parse the rest from our current position 1335 NFSubstitution::doParse(workText, parsePosition, withZeros ? 1 : baseValue, upperBound, FALSE, result); 1336 1337 if (withZeros) { 1338 // any base value will do in this case. is there a way to 1339 // force this to not bother trying all the base values? 1340 1341 // compute the 'effective' base and prescale the value down 1342 int64_t n = result.getLong(status); // force conversion! 1343 int64_t d = 1; 1344 int32_t pow = 0; 1345 while (d <= n) { 1346 d *= 10; 1347 ++pow; 1348 } 1349 // now add the zeros 1350 while (zeroCount > 0) { 1351 d *= 10; 1352 --zeroCount; 1353 } 1354 // d is now our true denominator 1355 result.setDouble((double)n/(double)d); 1356 } 1357 1358 return TRUE; 1359} 1360 1361UBool 1362NumeratorSubstitution::operator==(const NFSubstitution& rhs) const 1363{ 1364 return NFSubstitution::operator==(rhs) && 1365 denominator == ((const NumeratorSubstitution*)&rhs)->denominator; 1366} 1367 1368UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NumeratorSubstitution) 1369 1370const UChar NumeratorSubstitution::LTLT[] = { 0x003c, 0x003c }; 1371 1372//=================================================================== 1373// NullSubstitution 1374//=================================================================== 1375 1376UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NullSubstitution) 1377 1378U_NAMESPACE_END 1379 1380/* U_HAVE_RBNF */ 1381#endif 1382 1383