1 7 package com.ibm.icu.text; 8 9 import com.ibm.icu.impl.UCharacterProperty; 10 11 import java.text.*; 12 13 18 final class NFRule { 19 23 26 private static final String copyrightNotice 27 = "Copyright \u00a91997-1998 IBM Corp. All rights reserved."; 28 29 32 public static final int NEGATIVE_NUMBER_RULE = -1; 33 34 37 public static final int IMPROPER_FRACTION_RULE = -2; 38 39 42 public static final int PROPER_FRACTION_RULE = -3; 43 44 47 public static final int MASTER_RULE = -4; 48 49 53 56 private long baseValue; 57 58 62 private int radix = 10; 63 64 68 private short exponent = 0; 69 70 75 private String ruleText = null; 76 77 81 private NFSubstitution sub1 = null; 82 83 87 private NFSubstitution sub2 = null; 88 89 92 private RuleBasedNumberFormat formatter = null; 93 94 98 108 public static Object makeRules(String description, 109 NFRuleSet owner, 110 NFRule predecessor, 111 RuleBasedNumberFormat ownersOwner) { 112 NFRule rule1 = new NFRule(ownersOwner); 117 description = rule1.parseRuleDescriptor(description); 118 119 int brack1 = description.indexOf("["); 122 int brack2 = description.indexOf("]"); 123 124 if (brack1 == -1 || brack2 == -1 || brack1 > brack2 129 || rule1.getBaseValue() == PROPER_FRACTION_RULE 130 || rule1.getBaseValue() == NEGATIVE_NUMBER_RULE) { 131 rule1.ruleText = description; 132 rule1.extractSubstitutions(owner, predecessor, ownersOwner); 133 return rule1; 134 } else { 135 NFRule rule2 = null; 138 StringBuffer sbuf = new StringBuffer (); 139 140 if ((rule1.baseValue > 0 144 && rule1.baseValue % (Math.pow(rule1.radix, rule1.exponent)) == 0) 145 || rule1.baseValue == IMPROPER_FRACTION_RULE 146 || rule1.baseValue == MASTER_RULE) { 147 148 rule2 = new NFRule(ownersOwner); 154 if (rule1.baseValue >= 0) { 155 rule2.baseValue = rule1.baseValue; 156 if (!owner.isFractionSet()) { 157 ++rule1.baseValue; 158 } 159 } 160 161 else if (rule1.baseValue == IMPROPER_FRACTION_RULE) { 165 rule2.baseValue = PROPER_FRACTION_RULE; 166 } 167 168 else if (rule1.baseValue == MASTER_RULE) { 172 rule2.baseValue = rule1.baseValue; 173 rule1.baseValue = IMPROPER_FRACTION_RULE; 174 } 175 176 rule2.radix = rule1.radix; 179 rule2.exponent = rule1.exponent; 180 181 sbuf.append(description.substring(0, brack1)); 184 if (brack2 + 1 < description.length()) { 185 sbuf.append(description.substring(brack2 + 1)); 186 } 187 rule2.ruleText = sbuf.toString(); 188 rule2.extractSubstitutions(owner, predecessor, ownersOwner); 189 } 190 191 sbuf.setLength(0); 195 sbuf.append(description.substring(0, brack1)); 196 sbuf.append(description.substring(brack1 + 1, brack2)); 197 if (brack2 + 1 < description.length()) { 198 sbuf.append(description.substring(brack2 + 1)); 199 } 200 rule1.ruleText = sbuf.toString(); 201 rule1.extractSubstitutions(owner, predecessor, ownersOwner); 202 203 if (rule2 == null) { 209 return rule1; 210 } else { 211 return new NFRule[] { rule2, rule1 }; 212 } 213 } 214 } 215 216 220 public NFRule(RuleBasedNumberFormat formatter) { 221 this.formatter = formatter; 222 } 223 224 236 private String parseRuleDescriptor(String description) { 237 String descriptor; 238 239 int p = description.indexOf(":"); 243 if (p == -1) { 244 setBaseValue(0); 245 } else { 246 descriptor = description.substring(0, p); 250 ++p; 251 while (p < description.length() && UCharacterProperty.isRuleWhiteSpace(description.charAt(p))) 252 ++p; 253 description = description.substring(p); 254 255 if (descriptor.equals("-x")) { 259 setBaseValue(NEGATIVE_NUMBER_RULE); 260 } 261 else if (descriptor.equals("x.x")) { 262 setBaseValue(IMPROPER_FRACTION_RULE); 263 } 264 else if (descriptor.equals("0.x")) { 265 setBaseValue(PROPER_FRACTION_RULE); 266 } 267 else if (descriptor.equals("x.0")) { 268 setBaseValue(MASTER_RULE); 269 } 270 271 else if (descriptor.charAt(0) >= '0' && descriptor.charAt(0) <= '9') { 274 StringBuffer tempValue = new StringBuffer (); 275 p = 0; 276 char c = ' '; 277 278 while (p < descriptor.length()) { 283 c = descriptor.charAt(p); 284 if (c >= '0' && c <= '9') { 285 tempValue.append(c); 286 } 287 else if (c == '/' || c == '>') { 288 break; 289 } 290 else if (UCharacterProperty.isRuleWhiteSpace(c) || c == ',' || c == '.') { 291 } 292 else { 293 throw new IllegalArgumentException ("Illegal character in rule descriptor"); 294 } 295 ++p; 296 } 297 298 setBaseValue(Long.parseLong(tempValue.toString())); 302 303 if (c == '/') { 308 tempValue.setLength(0); 309 ++p; 310 while (p < descriptor.length()) { 311 c = descriptor.charAt(p); 312 if (c >= '0' && c <= '9') { 313 tempValue.append(c); 314 } 315 else if (c == '>') { 316 break; 317 } 318 else if (UCharacterProperty.isRuleWhiteSpace(c) || c == ',' || c == '.') { 319 } 320 else { 321 throw new IllegalArgumentException ("Illegal character is rule descriptor"); 322 } 323 ++p; 324 } 325 326 radix = Integer.parseInt(tempValue.toString()); 329 if (radix == 0) { 330 throw new IllegalArgumentException ("Rule can't have radix of 0"); 331 } 332 exponent = expectedExponent(); 333 } 334 335 if (c == '>') { 341 while (p < descriptor.length()) { 342 c = descriptor.charAt(p); 343 if (c == '>' && exponent > 0) { 344 --exponent; 345 } else { 346 throw new IllegalArgumentException ("Illegal character in rule descriptor"); 347 } 348 ++p; 349 } 350 } 351 } 352 } 353 354 if (description.length() > 0 && description.charAt(0) == '\'') { 358 description = description.substring(1); 359 } 360 361 return description; 364 } 365 366 374 private void extractSubstitutions(NFRuleSet owner, 375 NFRule predecessor, 376 RuleBasedNumberFormat ownersOwner) { 377 sub1 = extractSubstitution(owner, predecessor, ownersOwner); 378 sub2 = extractSubstitution(owner, predecessor, ownersOwner); 379 } 380 381 393 private NFSubstitution extractSubstitution(NFRuleSet owner, 394 NFRule predecessor, 395 RuleBasedNumberFormat ownersOwner) { 396 NFSubstitution result = null; 397 int subStart; 398 int subEnd; 399 400 subStart = indexOfAny(new String [] { "<<", "<%", "<#", "<0", 403 ">>", ">%", ">#", ">0", 404 "=%", "=#", "=0" } ); 405 406 if (subStart == -1) { 409 return NFSubstitution.makeSubstitution(ruleText.length(), this, predecessor, 410 owner, ownersOwner, ""); 411 } 412 413 if (ruleText.substring(subStart).startsWith(">>>")) { 416 subEnd = subStart + 2; 417 418 } else { 421 char c = ruleText.charAt(subStart); 422 subEnd = ruleText.indexOf(c, subStart + 1); 423 if (c == '<' && subEnd != -1 && subEnd < ruleText.length() - 1 && ruleText.charAt(subEnd+1) == c) { 425 ++subEnd; 430 } 431 } 432 433 if (subEnd == -1) { 437 return NFSubstitution.makeSubstitution(ruleText.length(), this, predecessor, 438 owner, ownersOwner, ""); 439 } 440 441 result = NFSubstitution.makeSubstitution(subStart, this, predecessor, owner, 445 ownersOwner, ruleText.substring(subStart, subEnd + 1)); 446 447 ruleText = ruleText.substring(0, subStart) + ruleText.substring(subEnd + 1); 449 return result; 450 } 451 452 459 public final void setBaseValue(long newBaseValue) { 460 baseValue = newBaseValue; 462 463 if (baseValue >= 1) { 469 radix = 10; 470 exponent = expectedExponent(); 471 472 if (sub1 != null) { 477 sub1.setDivisor(radix, exponent); 478 } 479 if (sub2 != null) { 480 sub2.setDivisor(radix, exponent); 481 } 482 483 } else { 486 radix = 10; 487 exponent = 0; 488 } 489 } 490 491 496 private short expectedExponent() { 497 if (radix == 0 || baseValue < 1) { 501 return 0; 502 } 503 504 short tempResult = (short)(Math.log(baseValue) / Math.log(radix)); 508 if (Math.pow(radix, tempResult + 1) <= baseValue) { 509 return (short)(tempResult + 1); 510 } else { 511 return tempResult; 512 } 513 } 514 515 524 private int indexOfAny(String [] strings) { 525 int pos; 526 int result = -1; 527 for (int i = 0; i < strings.length; i++) { 528 pos = ruleText.indexOf(strings[i]); 529 if (pos != -1 && (result == -1 || pos < result)) { 530 result = pos; 531 } 532 } 533 return result; 534 } 535 536 540 545 public boolean equals(Object that) { 546 if (that instanceof NFRule) { 547 NFRule that2 = (NFRule)that; 548 549 return baseValue == that2.baseValue 550 && radix == that2.radix 551 && exponent == that2.exponent 552 && ruleText.equals(that2.ruleText) 553 && sub1.equals(that2.sub1) 554 && sub2.equals(that2.sub2); 555 } 556 return false; 557 } 558 559 565 public String toString() { 566 StringBuffer result = new StringBuffer (); 567 568 if (baseValue == NEGATIVE_NUMBER_RULE) { 570 result.append("-x: "); 571 } 572 else if (baseValue == IMPROPER_FRACTION_RULE) { 573 result.append("x.x: "); 574 } 575 else if (baseValue == PROPER_FRACTION_RULE) { 576 result.append("0.x: "); 577 } 578 else if (baseValue == MASTER_RULE) { 579 result.append("x.0: "); 580 } 581 582 else { 589 result.append(String.valueOf(baseValue)); 590 if (radix != 10) { 591 result.append('/'); 592 result.append(String.valueOf(radix)); 593 } 594 int numCarets = expectedExponent() - exponent; 595 for (int i = 0; i < numCarets; i++) 596 result.append('>'); 597 result.append(": "); 598 } 599 600 if (ruleText.startsWith(" ") && (sub1 == null || sub1.getPos() != 0)) { 604 result.append("\'"); 605 } 606 607 StringBuffer ruleTextCopy = new StringBuffer (ruleText); 610 ruleTextCopy.insert(sub2.getPos(), sub2.toString()); 611 ruleTextCopy.insert(sub1.getPos(), sub1.toString()); 612 result.append(ruleTextCopy.toString()); 613 614 result.append(';'); 617 return result.toString(); 618 } 619 620 624 628 public final long getBaseValue() { 629 return baseValue; 630 } 631 632 637 public double getDivisor() { 638 return Math.pow(radix, exponent); 639 } 640 641 645 654 public void doFormat(long number, StringBuffer toInsertInto, int pos) { 655 toInsertInto.insert(pos, ruleText); 661 sub2.doSubstitution(number, toInsertInto, pos); 662 sub1.doSubstitution(number, toInsertInto, pos); 663 } 664 665 674 public void doFormat(double number, StringBuffer toInsertInto, int pos) { 675 toInsertInto.insert(pos, ruleText); 682 sub2.doSubstitution(number, toInsertInto, pos); 683 sub1.doSubstitution(number, toInsertInto, pos); 684 } 685 686 694 public boolean shouldRollBack(double number) { 695 if ((sub1.isModulusSubstitution()) || (sub2.isModulusSubstitution())) { 712 return (number % Math.pow(radix, exponent)) == 0 713 && (baseValue % Math.pow(radix, exponent)) != 0; 714 } 715 return false; 716 } 717 718 722 740 public Number doParse(String text, ParsePosition parsePosition, boolean isFractionRule, 741 double upperBound) { 742 743 ParsePosition pp = new ParsePosition(0); 746 String workText = new String (text); 747 748 workText = stripPrefix(workText, ruleText.substring(0, sub1.getPos()), pp); 753 int prefixLength = text.length() - workText.length(); 754 755 if (pp.getIndex() == 0 && sub1.getPos() != 0) { 756 return new Long (0); 759 } 760 761 int highWaterMark = 0; 791 double result = 0; 792 int start = 0; 793 double tempBaseValue = Math.max(0, baseValue); 794 795 do { 796 pp.setIndex(0); 801 double partialResult = matchToDelimiter(workText, start, tempBaseValue, 802 ruleText.substring(sub1.getPos(), sub2.getPos()), pp, sub1, 803 upperBound).doubleValue(); 804 805 if (pp.getIndex() != 0 || sub1.isNullSubstitution()) { 810 start = pp.getIndex(); 811 812 String workText2 = workText.substring(pp.getIndex()); 813 ParsePosition pp2 = new ParsePosition(0); 814 815 partialResult = matchToDelimiter(workText2, 0, partialResult, 820 ruleText.substring(sub2.getPos()), pp2, sub2, 821 upperBound).doubleValue(); 822 823 if (pp2.getIndex() != 0 || sub2.isNullSubstitution()) { 827 if (prefixLength + pp.getIndex() + pp2.getIndex() > highWaterMark) { 828 highWaterMark = prefixLength + pp.getIndex() + pp2.getIndex(); 829 result = partialResult; 830 } 831 } 832 } 840 } while (sub1.getPos() != sub2.getPos() && pp.getIndex() > 0 && pp.getIndex() 851 < workText.length() && pp.getIndex() != start); 852 853 parsePosition.setIndex(highWaterMark); 858 863 if (isFractionRule && highWaterMark > 0 && sub1.isNullSubstitution()) { 870 result = 1 / result; 871 } 872 873 if (result == (long)result) { 875 return new Long ((long)result); 876 } else { 877 return new Double (result); 878 } 879 } 880 881 897 private String stripPrefix(String text, String prefix, ParsePosition pp) { 898 if (prefix.length() == 0) { 900 return text; 901 } else { 902 int pfl = prefixLength(text, prefix); 907 if (pfl != 0) { 908 pp.setIndex(pp.getIndex() + pfl); 911 return text.substring(pfl); 912 913 } else { 915 return text; 916 } 917 } 918 } 919 920 946 private Number matchToDelimiter(String text, int startPos, double baseValue, 947 String delimiter, ParsePosition pp, NFSubstitution sub, double upperBound) { 948 if (!allIgnorable(delimiter)) { 953 ParsePosition tempPP = new ParsePosition(0); 954 Number tempResult; 955 956 int[] temp = findText(text, delimiter, startPos); 961 int dPos = temp[0]; 962 int dLen = temp[1]; 963 964 while (dPos >= 0) { 967 String subText = text.substring(0, dPos); 968 if (subText.length() > 0) { 969 tempResult = sub.doParse(subText, tempPP, baseValue, upperBound, 970 formatter.lenientParseEnabled()); 971 972 if (tempPP.getIndex() == dPos) { 979 pp.setIndex(dPos + dLen); 980 return tempResult; 981 } 982 } 991 992 tempPP.setIndex(0); 996 temp = findText(text, delimiter, dPos + dLen); 997 dPos = temp[0]; 998 dLen = temp[1]; 999 } 1000 pp.setIndex(0); 1003 return new Long (0); 1004 1005 } else { 1010 ParsePosition tempPP = new ParsePosition(0); 1011 Number result = new Long (0); 1012 Number tempResult; 1013 1014 tempResult = sub.doParse(text, tempPP, baseValue, upperBound, 1016 formatter.lenientParseEnabled()); 1017 if (tempPP.getIndex() != 0 || sub.isNullSubstitution()) { 1018 pp.setIndex(tempPP.getIndex()); 1023 if (tempResult != null) { 1024 result = tempResult; 1025 } 1026 } 1027 1032 return result; 1035 } 1036 } 1037 1038 1052 private int prefixLength(String str, String prefix) { 1053 if (prefix.length() == 0) { 1056 return 0; 1057 } 1058 1059 if (formatter.lenientParseEnabled()) { 1061 RuleBasedCollator collator = (RuleBasedCollator)formatter.getCollator(); 1075 CollationElementIterator strIter = collator.getCollationElementIterator(str); 1076 CollationElementIterator prefixIter = collator.getCollationElementIterator(prefix); 1077 1078 int oStr = strIter.next(); 1080 int oPrefix = prefixIter.next(); 1081 1082 while (oPrefix != CollationElementIterator.NULLORDER) { 1083 while (CollationElementIterator.primaryOrder(oStr) == 0 && oStr != 1085 CollationElementIterator.NULLORDER) { 1086 oStr = strIter.next(); 1087 } 1088 1089 while (CollationElementIterator.primaryOrder(oPrefix) == 0 && oPrefix != 1091 CollationElementIterator.NULLORDER) { 1092 oPrefix = prefixIter.next(); 1093 } 1094 1095 if (oPrefix == CollationElementIterator.NULLORDER) { 1098 break; 1099 } 1100 1101 if (oStr == CollationElementIterator.NULLORDER) { 1104 return 0; 1105 } 1106 1107 if (CollationElementIterator.primaryOrder(oStr) != CollationElementIterator. 1111 primaryOrder(oPrefix)) { 1112 return 0; 1113 } 1114 1118 oStr = strIter.next(); 1119 oPrefix = prefixIter.next(); 1120 } 1121 1122 int result = strIter.getOffset(); 1124 if (oStr != CollationElementIterator.NULLORDER) { 1125 --result; 1126 } 1127 return result; 1128 1129 1168 1169 } else { 1172 if (str.startsWith(prefix)) { 1173 return prefix.length(); 1174 } else { 1175 return 0; 1176 } 1177 } 1178 } 1179 1180 1193 private int[] findText(String str, String key) { 1194 return findText(str, key, 0); 1195 } 1196 1197 1212 private int[] findText(String str, String key, int startingAt) { 1213 if (!formatter.lenientParseEnabled()) { 1216 return new int[] { str.indexOf(key, startingAt), key.length() }; 1217 1218 } else { 1221 1224 int p = startingAt; 1230 int keyLen = 0; 1231 1232 while (p < str.length() && keyLen == 0) { 1240 keyLen = prefixLength(str.substring(p), key); 1241 if (keyLen != 0) { 1242 return new int[] { p, keyLen }; 1243 } 1244 ++p; 1245 } 1246 return new int[] { -1, 0 }; 1250 1251 } 1302 } 1303 1304 1312 private boolean allIgnorable(String str) { 1313 if (str.length() == 0) { 1315 return true; 1316 } 1317 1318 if (formatter.lenientParseEnabled()) { 1322 RuleBasedCollator collator = (RuleBasedCollator)(formatter.getCollator()); 1323 CollationElementIterator iter = collator.getCollationElementIterator(str); 1324 1325 int o = iter.next(); 1326 while (o != CollationElementIterator.NULLORDER 1327 && CollationElementIterator.primaryOrder(o) == 0) { 1328 o = iter.next(); 1329 } 1330 return o == CollationElementIterator.NULLORDER; 1331 } else { 1334 return false; 1335 } 1336 } 1337} 1338 | Popular Tags |