1 8 9 package com.ibm.icu.text; 10 11 import com.ibm.icu.impl.ICUDebug; 13 import com.ibm.icu.impl.ICUResourceBundle; 14 import com.ibm.icu.impl.UCharacterProperty; 15 import com.ibm.icu.impl.Utility; 16 import com.ibm.icu.util.ULocale; 17 import com.ibm.icu.util.UResourceBundle; 18 19 import java.math.BigInteger ; 20 import java.text.FieldPosition ; 21 import java.text.ParsePosition ; 22 import java.util.Arrays ; 23 import java.util.HashMap ; 24 import java.util.Locale ; 25 import java.util.Map ; 26 import java.util.MissingResourceException ; 27 import java.util.Set ; 28 29 31 32 487 public class RuleBasedNumberFormat extends NumberFormat { 488 489 493 static final long serialVersionUID = -7664252765575395068L; 495 496 499 private static final String copyrightNotice 500 = "Copyright \u00a91997-2004 IBM Corp. All rights reserved."; 501 502 506 public static final int SPELLOUT = 1; 507 508 512 public static final int ORDINAL = 2; 513 514 518 public static final int DURATION = 3; 519 520 524 527 private transient NFRuleSet[] ruleSets = null; 528 529 533 private transient NFRuleSet defaultRuleSet = null; 534 535 540 private ULocale locale = null; 541 542 547 private transient Collator collator = null; 548 549 554 private transient DecimalFormatSymbols decimalFormatSymbols = null; 555 556 560 private boolean lenientParse = false; 561 562 566 private transient String lenientParseRules; 567 568 572 private transient String postProcessRules; 573 574 577 private transient RBNFPostProcessor postProcessor; 578 579 583 private Map ruleSetDisplayNames; 584 585 589 private String [] publicRuleSetNames; 590 591 private static final boolean DEBUG = ICUDebug.enabled("rbnf"); 592 593 597 605 public RuleBasedNumberFormat(String description) { 606 locale = ULocale.getDefault(); 607 init(description, null); 608 } 609 610 632 public RuleBasedNumberFormat(String description, String [][] localizations) { 633 locale = ULocale.getDefault(); 634 init(description, localizations); 635 } 636 637 650 public RuleBasedNumberFormat(String description, Locale locale) { 651 this(description, ULocale.forLocale(locale)); 652 } 653 654 668 public RuleBasedNumberFormat(String description, ULocale locale) { 669 this.locale = locale; 670 init(description, null); 671 } 672 673 699 public RuleBasedNumberFormat(String description, String [][] localizations, ULocale locale) { 700 this.locale = locale; 701 init(description, localizations); 702 } 703 704 716 public RuleBasedNumberFormat(Locale locale, int format) { 717 this(ULocale.forLocale(locale), format); 718 } 719 720 733 public RuleBasedNumberFormat(ULocale locale, int format) { 734 this.locale = locale; 735 736 ICUResourceBundle bundle = (ICUResourceBundle)UResourceBundle. 737 getBundleInstance(ICUResourceBundle.ICU_RBNF_BASE_NAME, locale); 738 739 ULocale uloc = bundle.getULocale(); 743 setLocale(uloc, uloc); 744 745 String description = ""; 746 String [][] localizations = null; 747 748 try { 749 description = bundle.getString(rulenames[format-1]); 750 ICUResourceBundle locb = bundle.get(locnames[format-1]); 751 localizations = new String [locb.getSize()][]; 752 for (int i = 0; i < localizations.length; ++i) { 753 localizations[i] = locb.get(i).getStringArray(); 754 } 755 } 756 catch (MissingResourceException e) { 757 } 759 760 init(description, localizations); 761 } 762 763 private static final String [] rulenames = { 764 "SpelloutRules", "OrdinalRules", "DurationRules", 765 }; 766 private static final String [] locnames = { 767 "SpelloutLocalizations", "OrdinalLocalizations", "DurationLocalizations", 768 }; 769 770 780 public RuleBasedNumberFormat(int format) { 781 this(ULocale.getDefault(), format); 782 } 783 784 788 793 public Object clone() { 794 return super.clone(); 795 } 796 797 803 public boolean equals(Object that) { 804 if (!(that instanceof RuleBasedNumberFormat)) { 807 return false; 808 } else { 809 RuleBasedNumberFormat that2 = (RuleBasedNumberFormat)that; 812 813 if (!locale.equals(that2.locale) || lenientParse != that2.lenientParse) { 815 return false; 816 } 817 818 if (ruleSets.length != that2.ruleSets.length) { 820 return false; 821 } 822 for (int i = 0; i < ruleSets.length; i++) { 823 if (!ruleSets[i].equals(that2.ruleSets[i])) { 824 return false; 825 } 826 } 827 828 return true; 829 } 830 } 831 832 840 public String toString() { 841 842 StringBuffer result = new StringBuffer (); 845 for (int i = 0; i < ruleSets.length; i++) { 846 result.append(ruleSets[i].toString()); 847 } 848 return result.toString(); 849 } 850 851 855 private void writeObject(java.io.ObjectOutputStream out) 856 throws java.io.IOException { 857 out.writeUTF(this.toString()); 860 out.writeObject(this.locale); 861 } 862 863 867 private void readObject(java.io.ObjectInputStream in) 868 throws java.io.IOException , java.lang.ClassNotFoundException { 869 870 String description = in.readUTF(); 872 ULocale loc; 873 874 try { 875 loc = (ULocale) in.readObject(); 876 } catch (Exception e) { 877 loc = ULocale.getDefault(); 878 } 879 880 RuleBasedNumberFormat temp = new RuleBasedNumberFormat(description, loc); 885 ruleSets = temp.ruleSets; 886 defaultRuleSet = temp.defaultRuleSet; 887 publicRuleSetNames = temp.publicRuleSetNames; 888 decimalFormatSymbols = temp.decimalFormatSymbols; 889 locale = temp.locale; 890 } 891 892 893 897 902 public String [] getRuleSetNames() { 903 return (String [])publicRuleSetNames.clone(); 904 } 905 906 913 public ULocale[] getRuleSetDisplayNameLocales() { 914 if (ruleSetDisplayNames != null) { 915 Set s = ruleSetDisplayNames.keySet(); 916 String [] locales = (String [])s.toArray(new String [s.size()]); 917 Arrays.sort(locales, String.CASE_INSENSITIVE_ORDER); 918 ULocale[] result = new ULocale[locales.length]; 919 for (int i = 0; i < locales.length; ++i) { 920 result[i] = new ULocale(locales[i]); 921 } 922 return result; 923 } 924 return null; 925 } 926 927 private String [] getNameListForLocale(ULocale locale) { 928 if (locale != null && ruleSetDisplayNames != null) { 929 String [] localeNames = { locale.getBaseName(), ULocale.getDefault().getBaseName() }; 930 for (int i = 0; i < localeNames.length; ++i) { 931 String lname = localeNames[i]; 932 while (lname.length() > 0) { 933 String [] names = (String [])ruleSetDisplayNames.get(lname); 934 if (names != null) { 935 return names; 936 } 937 lname = ULocale.getFallback(lname); 938 } 939 } 940 } 941 return null; 942 } 943 944 955 public String [] getRuleSetDisplayNames(ULocale locale) { 956 String [] names = getNameListForLocale(locale); 957 if (names != null) { 958 return (String [])names.clone(); 959 } 960 names = getRuleSetNames(); 961 for (int i = 0; i < names.length; ++i) { 962 names[i] = names[i].substring(1); 963 } 964 return names; 965 } 966 967 974 public String [] getRuleSetDisplayNames() { 975 return getRuleSetDisplayNames(ULocale.getDefault()); 976 } 977 978 988 public String getRuleSetDisplayName(String ruleSetName, ULocale locale) { 989 String [] rsnames = publicRuleSetNames; 990 for (int ix = 0; ix < rsnames.length; ++ix) { 991 if (rsnames[ix].equals(ruleSetName)) { 992 String [] names = getNameListForLocale(locale); 993 if (names != null) { 994 return names[ix]; 995 } 996 return rsnames[ix].substring(1); 997 } 998 } 999 throw new IllegalArgumentException ("unrecognized rule set name: " + ruleSetName); 1000 } 1001 1002 1009 public String getRuleSetDisplayName(String ruleSetName) { 1010 return getRuleSetDisplayName(ruleSetName, ULocale.getDefault()); 1011 } 1012 1013 1021 public String format(double number, String ruleSet) throws IllegalArgumentException { 1022 if (ruleSet.startsWith("%%")) { 1023 throw new IllegalArgumentException ("Can't use internal rule set"); 1024 } 1025 return format(number, findRuleSet(ruleSet)); 1026 } 1027 1028 1040 public String format(long number, String ruleSet) throws IllegalArgumentException { 1041 if (ruleSet.startsWith("%%")) { 1042 throw new IllegalArgumentException ("Can't use internal rule set"); 1043 } 1044 return format(number, findRuleSet(ruleSet)); 1045 } 1046 1047 1056 public StringBuffer format(double number, 1057 StringBuffer toAppendTo, 1058 FieldPosition ignore) { 1059 toAppendTo.append(format(number, defaultRuleSet)); 1063 return toAppendTo; 1064 } 1065 1066 1079 public StringBuffer format(long number, 1080 StringBuffer toAppendTo, 1081 FieldPosition ignore) { 1082 toAppendTo.append(format(number, defaultRuleSet)); 1086 return toAppendTo; 1087 } 1088 1089 1095 public StringBuffer format(BigInteger number, 1096 StringBuffer toAppendTo, 1097 FieldPosition pos) { 1098 return format(new com.ibm.icu.math.BigDecimal(number), toAppendTo, pos); 1099 } 1100 1101 1115 1121 public StringBuffer format(com.ibm.icu.math.BigDecimal number, 1122 StringBuffer toAppendTo, 1123 FieldPosition pos) { 1124 return format(number.doubleValue(), toAppendTo, pos); 1126 } 1127 1128 1144 public Number parse(String text, ParsePosition parsePosition) { 1145 1146 String workingText = text.substring(parsePosition.getIndex()); 1151 ParsePosition workingPos = new ParsePosition (0); 1152 Number tempResult = null; 1153 1154 Number result = new Long (0); 1157 ParsePosition highWaterMark = new ParsePosition (workingPos.getIndex()); 1158 1159 for (int i = ruleSets.length - 1; i >= 0; i--) { 1164 if (ruleSets[i].getName().startsWith("%%")) { 1166 continue; 1167 } 1168 1169 tempResult = ruleSets[i].parse(workingText, workingPos, Double.MAX_VALUE); 1172 if (workingPos.getIndex() > highWaterMark.getIndex()) { 1173 result = tempResult; 1174 highWaterMark.setIndex(workingPos.getIndex()); 1175 } 1176 1181 if (highWaterMark.getIndex() == workingText.length()) { 1184 break; 1185 } 1186 1187 workingPos.setIndex(0); 1190 } 1191 1192 parsePosition.setIndex(parsePosition.getIndex() + highWaterMark.getIndex()); 1195 return result; 1200 } 1201 1202 1235 public void setLenientParseMode(boolean enabled) { 1236 lenientParse = enabled; 1237 1238 if (!enabled) { 1241 collator = null; 1242 } 1243 } 1244 1245 1252 public boolean lenientParseEnabled() { 1253 return lenientParse; 1254 } 1255 1256 1263 public void setDefaultRuleSet(String ruleSetName) { 1264 if (ruleSetName == null) { 1265 if (publicRuleSetNames.length > 0) { 1266 defaultRuleSet = findRuleSet(publicRuleSetNames[0]); 1267 } else { 1268 defaultRuleSet = null; 1269 int n = ruleSets.length; 1270 while (--n >= 0) { 1271 if (ruleSets[n].isPublic()) { 1272 defaultRuleSet = ruleSets[n]; 1273 break; 1274 } 1275 } 1276 } 1277 } else if (ruleSetName.startsWith("%%")) { 1278 throw new IllegalArgumentException ("cannot use private rule set: " + ruleSetName); 1279 } else { 1280 defaultRuleSet = findRuleSet(ruleSetName); 1281 } 1282 } 1283 1284 1289 public String getDefaultRuleSetName() { 1290 if (defaultRuleSet != null && defaultRuleSet.isPublic()) { 1291 return defaultRuleSet.getName(); 1292 } 1293 return ""; 1294 } 1295 1296 1300 1306 NFRuleSet getDefaultRuleSet() { 1307 return defaultRuleSet; 1308 } 1309 1310 1316 Collator getCollator() { 1317 if (collator == null && lenientParse) { 1319 try { 1320 RuleBasedCollator temp = (RuleBasedCollator)Collator.getInstance(locale); 1325 String rules = temp.getRules() + lenientParseRules; 1326 1327 collator = new RuleBasedCollator(rules); 1328 collator.setDecomposition(Collator.CANONICAL_DECOMPOSITION); 1329 } 1330 catch (Exception e) { 1331 if(DEBUG){ 1334 e.printStackTrace(); 1335 } 1336 collator = null; 1337 } 1338 } 1339 1340 return collator; 1343 } 1344 1345 1352 DecimalFormatSymbols getDecimalFormatSymbols() { 1353 if (decimalFormatSymbols == null) { 1357 decimalFormatSymbols = new DecimalFormatSymbols(locale); 1358 } 1359 return decimalFormatSymbols; 1360 } 1361 1362 1366 1377 private String extractSpecial(StringBuffer description, String specialName) { 1378 String result = null; 1379 int lp = Utility.indexOf(description, specialName); 1380 if (lp != -1) { 1381 if (lp == 0 || description.charAt(lp - 1) == ';') { 1385 int lpEnd = Utility.indexOf(description, ";%", lp); 1389 1390 if (lpEnd == -1) { 1391 lpEnd = description.length() - 1; } 1393 int lpStart = lp + specialName.length(); 1394 while (lpStart < lpEnd && 1395 UCharacterProperty.isRuleWhiteSpace(description.charAt(lpStart))) { 1396 ++lpStart; 1397 } 1398 1399 result = description.substring(lpStart, lpEnd); 1401 1402 description.delete(lp, lpEnd+1); } 1405 } 1406 return result; 1407 } 1408 1409 1417 private void init(String description, String [][] localizations) { 1418 initLocalizations(localizations); 1419 1420 StringBuffer descBuf = stripWhitespace(description); 1426 1427 1432 lenientParseRules = extractSpecial(descBuf, "%%lenient-parse:"); 1433 postProcessRules = extractSpecial(descBuf, "%%post-process:"); 1434 1435 int numRuleSets = 0; 1439 for (int p = Utility.indexOf(descBuf, ";%"); p != -1; p = Utility.indexOf(descBuf, ";%", p)) { 1440 ++numRuleSets; 1441 ++p; 1442 } 1443 ++numRuleSets; 1444 1445 ruleSets = new NFRuleSet[numRuleSets]; 1447 1448 String [] ruleSetDescriptions = new String [numRuleSets]; 1456 1457 int curRuleSet = 0; 1458 int start = 0; 1459 for (int p = Utility.indexOf(descBuf, ";%"); p != -1; p = Utility.indexOf(descBuf, ";%", start)) { 1460 ruleSetDescriptions[curRuleSet] = descBuf.substring(start, p + 1); 1461 ruleSets[curRuleSet] = new NFRuleSet(ruleSetDescriptions, curRuleSet); 1462 ++curRuleSet; 1463 start = p + 1; 1464 } 1465 ruleSetDescriptions[curRuleSet] = descBuf.substring(start); 1466 ruleSets[curRuleSet] = new NFRuleSet(ruleSetDescriptions, curRuleSet); 1467 1468 1474 defaultRuleSet = ruleSets[ruleSets.length - 1]; 1478 for (int i = ruleSets.length - 1; i >= 0; --i) { 1479 if (!ruleSets[i].getName().startsWith("%%")) { 1480 defaultRuleSet = ruleSets[i]; 1481 break; 1482 } 1483 } 1484 1485 for (int i = 0; i < ruleSets.length; i++) { 1489 ruleSets[i].parseRules(ruleSetDescriptions[i], this); 1490 ruleSetDescriptions[i] = null; 1491 } 1492 1493 1496 int publicRuleSetCount = 0; 1499 for (int i = 0; i < ruleSets.length; i++) { 1500 if (!ruleSets[i].getName().startsWith("%%")) { 1501 ++publicRuleSetCount; 1502 } 1503 } 1504 1505 String [] publicRuleSetTemp = new String [publicRuleSetCount]; 1507 publicRuleSetCount = 0; 1508 for (int i = ruleSets.length - 1; i >= 0; i--) { 1509 if (!ruleSets[i].getName().startsWith("%%")) { 1510 publicRuleSetTemp[publicRuleSetCount++] = ruleSets[i].getName(); 1511 } 1512 } 1513 1514 if (publicRuleSetNames != null) { 1515 loop: for (int i = 0; i < publicRuleSetNames.length; ++i) { 1518 String name = publicRuleSetNames[i]; 1519 for (int j = 0; j < publicRuleSetTemp.length; ++j) { 1520 if (name.equals(publicRuleSetTemp[j])) { 1521 continue loop; 1522 } 1523 } 1524 throw new IllegalArgumentException ("did not find public rule set: " + name); 1525 } 1526 1527 defaultRuleSet = findRuleSet(publicRuleSetNames[0]); } else { 1529 publicRuleSetNames = publicRuleSetTemp; 1530 } 1531 } 1532 1533 1537 private void initLocalizations(String [][] localizations) { 1538 if (localizations != null) { 1539 publicRuleSetNames = (String [])localizations[0].clone(); 1540 1541 Map m = new HashMap (); 1542 for (int i = 1; i < localizations.length; ++i) { 1543 String [] data = localizations[i]; 1544 String locale = data[0]; 1545 String [] names = new String [data.length-1]; 1546 if (names.length != publicRuleSetNames.length) { 1547 throw new IllegalArgumentException ("public name length: " + publicRuleSetNames.length + 1548 " != localized names[" + i + "] length: " + names.length); 1549 } 1550 System.arraycopy(data, 1, names, 0, names.length); 1551 m.put(locale, names); 1552 } 1553 1554 if (!m.isEmpty()) { 1555 ruleSetDisplayNames = m; 1556 } 1557 } 1558 } 1559 1560 1567 private StringBuffer stripWhitespace(String description) { 1568 StringBuffer result = new StringBuffer (); 1571 1572 int start = 0; 1574 while (start != -1 && start < description.length()) { 1575 while (start < description.length() 1577 && UCharacterProperty.isRuleWhiteSpace(description.charAt(start))) { 1578 ++start; 1579 } 1580 1581 if (start < description.length() && description.charAt(start) == ';') { 1583 start += 1; 1584 continue; 1585 } 1586 1587 int p; 1590 p = description.indexOf(';', start); 1591 if (p == -1) { 1592 result.append(description.substring(start)); 1595 start = -1; 1596 } 1597 else if (p < description.length()) { 1598 result.append(description.substring(start, p + 1)); 1599 start = p + 1; 1600 } 1601 1602 else { 1607 start = -1; 1608 } 1609 } 1610 return result; 1611 } 1612 1613 1621 private void initDefaultRuleSet() { 1622 for (int i = ruleSets.length - 1; i >= 0; --i) { 1625 if (!ruleSets[i].getName().startsWith("%%")) { 1626 defaultRuleSet = ruleSets[i]; 1627 return; 1628 } 1629 } 1630 defaultRuleSet = ruleSets[ruleSets.length - 1]; 1631 } 1632 1633 1637 1645 private String format(double number, NFRuleSet ruleSet) { 1646 StringBuffer result = new StringBuffer (); 1652 ruleSet.format(number, result, 0); 1653 postProcess(result, ruleSet); 1654 return result.toString(); 1655 } 1656 1657 1665 private String format(long number, NFRuleSet ruleSet) { 1666 StringBuffer result = new StringBuffer (); 1677 ruleSet.format(number, result, 0); 1678 postProcess(result, ruleSet); 1679 return result.toString(); 1680 } 1681 1682 1685 private void postProcess(StringBuffer result, NFRuleSet ruleSet) { 1686 if (postProcessRules != null) { 1687 if (postProcessor == null) { 1688 int ix = postProcessRules.indexOf(";"); 1689 if (ix == -1) { 1690 ix = postProcessRules.length(); 1691 } 1692 String ppClassName = postProcessRules.substring(0, ix).trim(); 1693 try { 1694 Class cls = Class.forName(ppClassName); 1695 postProcessor = (RBNFPostProcessor)cls.newInstance(); 1696 postProcessor.init(this, postProcessRules); 1697 } 1698 catch (Exception e) { 1699 System.out.println("could not locate " + ppClassName + ", error " + 1701 e.getClass().getName() + ", " + e.getMessage()); 1702 postProcessor = null; 1703 postProcessRules = null; return; 1705 } 1706 } 1707 1708 postProcessor.process(result, ruleSet); 1709 } 1710 } 1711 1712 1718 NFRuleSet findRuleSet(String name) throws IllegalArgumentException { 1719 for (int i = 0; i < ruleSets.length; i++) { 1720 if (ruleSets[i].getName().equals(name)) { 1721 return ruleSets[i]; 1722 } 1723 } 1724 throw new IllegalArgumentException ("No rule set named " + name); 1725 } 1726} 1727 | Popular Tags |