1 7 package com.ibm.icu.text; 8 9 import com.ibm.icu.impl.UCharacterProperty; 10 import com.ibm.icu.impl.Utility; 11 12 import java.text.*; 13 import java.util.Vector ; 14 15 22 23 final class NFRuleSet { 24 28 31 private static final String copyrightNotice 32 = "Copyright \u00a91997-1998 IBM Corp. All rights reserved."; 33 34 38 41 private String name; 42 43 46 private NFRule[] rules; 47 48 51 private NFRule negativeNumberRule = null; 52 53 58 private NFRule[] fractionRules = new NFRule[3]; 59 60 68 private boolean isFractionRuleSet = false; 69 70 73 private int recursionCount = 0; 74 75 78 private static final int RECURSION_LIMIT = 50; 79 80 84 92 public NFRuleSet(String [] descriptions, int index) throws IllegalArgumentException { 93 String description = descriptions[index]; 94 95 if (description.length() == 0) { 96 throw new IllegalArgumentException ("Empty rule set description"); 97 } 98 99 if (description.charAt(0) == '%') { 104 int pos = description.indexOf(':'); 105 if (pos == -1) { 106 throw new IllegalArgumentException ("Rule set name doesn't end in colon"); 107 } else { 108 name = description.substring(0, pos); 109 while (pos < description.length() && UCharacterProperty.isRuleWhiteSpace(description. 110 charAt(++pos))) { 111 } 112 description = description.substring(pos); 113 descriptions[index] = description; 114 } 115 116 } else { 119 name = "%default"; 120 } 121 122 if (description.length() == 0) { 123 throw new IllegalArgumentException ("Empty rule set description"); 124 } 125 126 } 129 130 140 public void parseRules(String description, 141 RuleBasedNumberFormat owner) { 142 Vector ruleDescriptions = new Vector (); 147 148 int oldP = 0; 149 int p = description.indexOf(';'); 150 while (oldP != -1) { 151 if (p != -1) { 152 ruleDescriptions.addElement(description.substring(oldP, p)); 153 oldP = p + 1; 154 } else { 155 if (oldP < description.length()) { 156 ruleDescriptions.addElement(description.substring(oldP)); 157 } 158 oldP = p; 159 } 160 p = description.indexOf(';', p + 1); 161 } 162 163 Vector tempRules = new Vector (); 167 168 NFRule predecessor = null; 171 for (int i = 0; i < ruleDescriptions.size(); i++) { 172 Object temp = NFRule.makeRules((String )ruleDescriptions.elementAt(i), 176 this, predecessor, owner); 177 178 if (temp instanceof NFRule) { 179 tempRules.addElement(temp); 180 predecessor = (NFRule)temp; 181 } 182 else if (temp instanceof NFRule[]) { 183 NFRule[] rulesToAdd = (NFRule[])temp; 184 185 for (int j = 0; j < rulesToAdd.length; j++) { 186 tempRules.addElement(rulesToAdd[j]); 187 predecessor = rulesToAdd[j]; 188 } 189 } 190 } 191 ruleDescriptions = null; 193 194 long defaultBaseValue = 0; 199 200 int i = 0; 204 while (i < tempRules.size()) { 205 NFRule rule = (NFRule)tempRules.elementAt(i); 206 207 switch ((int)rule.getBaseValue()) { 208 case 0: 214 rule.setBaseValue(defaultBaseValue); 215 if (!isFractionRuleSet) { 216 ++defaultBaseValue; 217 } 218 ++i; 219 break; 220 221 case NFRule.NEGATIVE_NUMBER_RULE: 224 negativeNumberRule = rule; 225 tempRules.removeElementAt(i); 226 break; 227 228 case NFRule.IMPROPER_FRACTION_RULE: 231 fractionRules[0] = rule; 232 tempRules.removeElementAt(i); 233 break; 234 235 case NFRule.PROPER_FRACTION_RULE: 238 fractionRules[1] = rule; 239 tempRules.removeElementAt(i); 240 break; 241 242 case NFRule.MASTER_RULE: 245 fractionRules[2] = rule; 246 tempRules.removeElementAt(i); 247 break; 248 249 default: 253 if (rule.getBaseValue() < defaultBaseValue) { 254 throw new IllegalArgumentException ("Rules are not in order, base: " + 255 rule.getBaseValue() + " < " + defaultBaseValue); 256 } 257 defaultBaseValue = rule.getBaseValue(); 258 if (!isFractionRuleSet) { 259 ++defaultBaseValue; 260 } 261 ++i; 262 break; 263 } 264 } 265 266 rules = new NFRule[tempRules.size()]; 269 tempRules.copyInto((Object [])rules); 270 } 271 272 280 public void makeIntoFractionRuleSet() { 281 isFractionRuleSet = true; 282 } 283 284 288 293 public boolean equals(Object that) { 294 if (!(that instanceof NFRuleSet)) { 296 return false; 297 } else { 298 NFRuleSet that2 = (NFRuleSet)that; 300 301 if (!name.equals(that2.name) 302 || !Utility.objectEquals(negativeNumberRule, that2.negativeNumberRule) 303 || !Utility.objectEquals(fractionRules[0], that2.fractionRules[0]) 304 || !Utility.objectEquals(fractionRules[1], that2.fractionRules[1]) 305 || !Utility.objectEquals(fractionRules[2], that2.fractionRules[2]) 306 || rules.length != that2.rules.length 307 || isFractionRuleSet != that2.isFractionRuleSet) { 308 309 return false; 310 } 311 312 for (int i = 0; i < rules.length; i++) { 314 if (!rules[i].equals(that2.rules[i])) { 315 return false; 316 } 317 } 318 319 return true; 321 } 322 } 323 324 325 331 public String toString() { 332 StringBuffer result = new StringBuffer (); 333 334 result.append(name + ":\n"); 336 337 for (int i = 0; i < rules.length; i++) { 339 result.append(" " + rules[i].toString() + "\n"); 340 } 341 342 if (negativeNumberRule != null) { 344 result.append(" " + negativeNumberRule.toString() + "\n"); 345 } 346 if (fractionRules[0] != null) { 347 result.append(" " + fractionRules[0].toString() + "\n"); 348 } 349 if (fractionRules[1] != null) { 350 result.append(" " + fractionRules[1].toString() + "\n"); 351 } 352 if (fractionRules[2] != null) { 353 result.append(" " + fractionRules[2].toString() + "\n"); 354 } 355 356 return result.toString(); 357 } 358 359 363 367 public boolean isFractionSet() { 368 return isFractionRuleSet; 369 } 370 371 375 public String getName() { 376 return name; 377 } 378 379 383 public boolean isPublic() { 384 return !name.startsWith("%%"); 385 } 386 387 391 399 public void format(long number, StringBuffer toInsertInto, int pos) { 400 NFRule applicableRule = findNormalRule(number); 401 402 if (++recursionCount >= RECURSION_LIMIT) { 403 recursionCount = 0; 404 throw new IllegalStateException ("Recursion limit exceeded when applying ruleSet " + name); 405 } 406 applicableRule.doFormat(number, toInsertInto, pos); 407 --recursionCount; 408 } 409 410 418 public void format(double number, StringBuffer toInsertInto, int pos) { 419 NFRule applicableRule = findRule(number); 420 421 if (++recursionCount >= RECURSION_LIMIT) { 422 recursionCount = 0; 423 throw new IllegalStateException ("Recursion limit exceeded when applying ruleSet " + name); 424 } 425 applicableRule.doFormat(number, toInsertInto, pos); 426 --recursionCount; 427 } 428 429 434 private NFRule findRule(double number) { 435 if (isFractionRuleSet) { 437 return findFractionRuleSetRule(number); 438 } 439 440 if (number < 0) { 444 if (negativeNumberRule != null) { 445 return negativeNumberRule; 446 } else { 447 number = -number; 448 } 449 } 450 451 if (number != Math.floor(number)) { 453 if (number < 1 && fractionRules[1] != null) { 456 return fractionRules[1]; 457 } 458 459 else if (fractionRules[0] != null) { 461 return fractionRules[0]; 462 } 463 } 464 465 if (fractionRules[2] != null) { 467 return fractionRules[2]; 468 469 } else { 472 return findNormalRule((long)Math.round(number)); 473 } 474 } 475 476 492 private NFRule findNormalRule(long number) { 493 if (isFractionRuleSet) { 497 return findFractionRuleSetRule(number); 498 } 499 500 if (number < 0) { 503 if (negativeNumberRule != null) { 504 return negativeNumberRule; 505 } else { 506 number = -number; 507 } 508 } 509 510 519 int lo = 0; 523 int hi = rules.length; 524 if (hi > 0) { 525 while (lo < hi) { 526 int mid = (lo + hi) / 2; 527 if (rules[mid].getBaseValue() == number) { 528 return rules[mid]; 529 } 530 else if (rules[mid].getBaseValue() > number) { 531 hi = mid; 532 } 533 else { 534 lo = mid + 1; 535 } 536 } 537 if (hi == 0) { throw new IllegalStateException ("The rule set " + name + " cannot format the value " + number); 539 } 540 NFRule result = rules[hi - 1]; 541 542 if (result.shouldRollBack(number)) { 548 if (hi == 1) { throw new IllegalStateException ("The rule set " + name + " cannot roll back from the rule '" + 550 result + "'"); 551 } 552 result = rules[hi - 2]; 553 } 554 return result; 555 } 556 return fractionRules[2]; 558 } 559 560 575 private NFRule findFractionRuleSetRule(double number) { 576 581 long leastCommonMultiple = rules[0].getBaseValue(); 586 for (int i = 1; i < rules.length; i++) { 587 leastCommonMultiple = lcm(leastCommonMultiple, rules[i].getBaseValue()); 588 } 589 long numerator = (long)(Math.round(number * leastCommonMultiple)); 590 591 long tempDifference; 593 long difference = Long.MAX_VALUE; 594 int winner = 0; 595 for (int i = 0; i < rules.length; i++) { 596 tempDifference = numerator * rules[i].getBaseValue() % leastCommonMultiple; 603 604 if (leastCommonMultiple - tempDifference < tempDifference) { 608 tempDifference = leastCommonMultiple - tempDifference; 609 } 610 611 if (tempDifference < difference) { 616 difference = tempDifference; 617 winner = i; 618 if (difference == 0) { 619 break; 620 } 621 } 622 } 623 624 if (winner + 1 < rules.length 631 && rules[winner + 1].getBaseValue() == rules[winner].getBaseValue()) { 632 if (Math.round(number * rules[winner].getBaseValue()) < 1 633 || Math.round(number * rules[winner].getBaseValue()) >= 2) { 634 ++winner; 635 } 636 } 637 638 return rules[winner]; 640 } 641 642 645 private static long lcm(long x, long y) { 646 long x1 = x; 649 long y1 = y; 650 651 int p2 = 0; 652 while ((x1 & 1) == 0 && (y1 & 1) == 0) { 653 ++p2; 654 x1 >>= 1; 655 y1 >>= 1; 656 } 657 658 long t; 659 if ((x1 & 1) == 1) { 660 t = -y1; 661 } else { 662 t = x1; 663 } 664 665 while (t != 0) { 666 while ((t & 1) == 0) { 667 t >>= 1; 668 } 669 if (t > 0) { 670 x1 = t; 671 } else { 672 y1 = -t; 673 } 674 t = x1 - y1; 675 } 676 long gcd = x1 << p2; 677 678 return x / gcd * y; 680 } 681 682 686 707 public Number parse(String text, ParsePosition parsePosition, double upperBound) { 708 712 ParsePosition highWaterMark = new ParsePosition(0); 713 Number result = new Long (0); 714 Number tempResult = null; 715 716 if (text.length() == 0) { 718 return result; 719 } 720 721 if (negativeNumberRule != null) { 723 tempResult = negativeNumberRule.doParse(text, parsePosition, false, upperBound); 724 if (parsePosition.getIndex() > highWaterMark.getIndex()) { 725 result = tempResult; 726 highWaterMark.setIndex(parsePosition.getIndex()); 727 } 728 parsePosition.setIndex(0); 733 } 734 735 for (int i = 0; i < 3; i++) { 737 if (fractionRules[i] != null) { 738 tempResult = fractionRules[i].doParse(text, parsePosition, false, upperBound); 739 if (parsePosition.getIndex() > highWaterMark.getIndex()) { 740 result = tempResult; 741 highWaterMark.setIndex(parsePosition.getIndex()); 742 } 743 parsePosition.setIndex(0); 748 } 749 } 750 751 for (int i = rules.length - 1; i >= 0 && highWaterMark.getIndex() < text.length(); i--) { 761 if (!isFractionRuleSet && rules[i].getBaseValue() >= upperBound) { 762 continue; 763 } 764 765 tempResult = rules[i].doParse(text, parsePosition, isFractionRuleSet, upperBound); 766 if (parsePosition.getIndex() > highWaterMark.getIndex()) { 767 result = tempResult; 768 highWaterMark.setIndex(parsePosition.getIndex()); 769 } 770 parsePosition.setIndex(0); 775 } 776 777 parsePosition.setIndex(highWaterMark.getIndex()); 781 786 return result; 787 } 788 } 789 | Popular Tags |