home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / text / CollationElementIterator.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  14.3 KB  |  436 lines

  1. /*
  2.  * @(#)CollationElementIterator.java    1.20 98/03/18
  3.  *
  4.  * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
  5.  * (C) Copyright IBM Corp. 1996, 1997 - All Rights Reserved
  6.  *
  7.  * Portions copyright (c) 1996-1998 Sun Microsystems, Inc. All Rights Reserved.
  8.  *
  9.  *   The original version of this source code and documentation is copyrighted
  10.  * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  11.  * materials are provided under terms of a License Agreement between Taligent
  12.  * and Sun. This technology is protected by multiple US and International
  13.  * patents. This notice and attribution to Taligent may not be removed.
  14.  *   Taligent is a registered trademark of Taligent, Inc.
  15.  *
  16.  * Permission to use, copy, modify, and distribute this software
  17.  * and its documentation for NON-COMMERCIAL purposes and without
  18.  * fee is hereby granted provided that this copyright notice
  19.  * appears in all copies. Please refer to the file "copyright.html"
  20.  * for further important copyright and licensing information.
  21.  *
  22.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
  23.  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  24.  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  25.  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
  26.  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  27.  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  28.  *
  29.  */
  30.  
  31. package java.text;
  32.  
  33. import java.lang.Character;
  34. import java.util.Vector;
  35.  
  36. /**
  37.  * The <code>CollationElementIterator</code> class is used as an iterator
  38.  * to walk through each character of an international string. Use the iterator
  39.  * to return the ordering priority of the positioned character. The ordering
  40.  * priority of a character, which we refer to as a key, defines how a character
  41.  * is collated in the given collation object.
  42.  *
  43.  * <p>
  44.  * For example, consider the following in Spanish:
  45.  * <blockquote>
  46.  * <pre>
  47.  * "ca" -> the first key is key('c') and second key is key('a').
  48.  * "cha" -> the first key is key('ch') and second key is key('a').
  49.  * </pre>
  50.  * </blockquote>
  51.  * And in German,
  52.  * <blockquote>
  53.  * <pre>
  54.  * "\u00e4b"-> the first key is key('a'), the second key is key('e'), and
  55.  * the third key is key('b').
  56.  * </pre>
  57.  * </blockquote>
  58.  * The key of a character is an integer composed of primary order(short),
  59.  * secondary order(byte), and tertiary order(byte). Java strictly defines
  60.  * the size and signedness of its primitive data types. Therefore, the static
  61.  * functions <code>primaryOrder</code>, <code>secondaryOrder</code>, and
  62.  * <code>tertiaryOrder</code> return <code>int</code>, <code>short</code>,
  63.  * and <code>short</code> respectively to ensure the correctness of the key
  64.  * value.
  65.  *
  66.  * <p>
  67.  * Example of the iterator usage,
  68.  * <blockquote>
  69.  * <pre>
  70.  * // get the first key of the string
  71.  * String str = "This is a test";
  72.  * CollationElementIterator c =
  73.  *     new CollationElementIterator(str, 0, str.length(),
  74.  *                                  Collator.getInstance());
  75.  * int primaryOrder = CollationElementIterator.primaryOrder(c->next());
  76.  * </pre>
  77.  * </blockquote>
  78.  *
  79.  * <p>
  80.  * <code>CollationElementIterator.next</code> returns the collation order
  81.  * of the next character. A collation order consists of primary order,
  82.  * secondary order and tertiary order. The data type of the collation
  83.  * order is <strong>int</strong>. The first 16 bits of a collation order
  84.  * is its primary order; the next 8 bits is the secondary order and the
  85.  * last 8 bits is the tertiary order.
  86.  *
  87.  * @see                Collator
  88.  * @see                RuleBasedCollator
  89.  * @version            1.20 03/18/98
  90.  * @author             Helena Shih
  91.  */
  92. public final class CollationElementIterator
  93. {
  94.     /**
  95.      * Null order which indicates the end of string is reached by the
  96.      * cursor.
  97.      */
  98.     public final static int NULLORDER = 0xffffffff;
  99.  
  100.     /**
  101.      * CollationElementIterator constructor.  This takes the source string and
  102.      * the collation object.  The cursor will walk thru the source string based
  103.      * on the predefined collation rules.  If the source string is empty,
  104.      * NULLORDER will be returned on the calls to next().
  105.      * @param sourceText the source string.
  106.      * @param order the collation object.
  107.      */
  108.     CollationElementIterator(String sourceText, RuleBasedCollator order) {
  109.         ordering = order;
  110.         if ( sourceText.length() != 0 ) {
  111.             text = new Normalizer(sourceText, order.getDecomposition());
  112.         }
  113.     }
  114.  
  115.     /**
  116.      * CollationElementIterator constructor.  This takes the source string and
  117.      * the collation object.  The cursor will walk thru the source string based
  118.      * on the predefined collation rules.  If the source string is empty,
  119.      * NULLORDER will be returned on the calls to next().
  120.      * @param sourceText the source string.
  121.      * @param order the collation object.
  122.      */
  123.     CollationElementIterator(CharacterIterator sourceText, RuleBasedCollator order) {
  124.         ordering = order;
  125.         text = new Normalizer(sourceText, order.getDecomposition());
  126.     }
  127.     /**
  128.      * Resets the cursor to the beginning of the string.
  129.      */
  130.     public void reset()
  131.     {
  132.         if (text != null) {
  133.             text.reset();
  134.             text.setDecomposition(ordering.getDecomposition());
  135.         }
  136.         buffer = null;
  137.         expIndex = 0;
  138.         swapOrder = 0;
  139.     }
  140.  
  141.     /**
  142.      * Get the ordering priority of the next character in the string.
  143.      * @return the next character's ordering.  Returns NULLORDER if
  144.      * the end of string is reached.
  145.      */
  146.     public int next()
  147.     {
  148.         if (text == null)
  149.             return NULLORDER;
  150.         if (text.getDecomposition() != ordering.getDecomposition())
  151.             text.setDecomposition(ordering.getDecomposition());
  152.         if (buffer != null)
  153.         {
  154.             if (expIndex < buffer.length)
  155.             {
  156.                 return strengthOrder(buffer[expIndex++]);
  157.             }
  158.             else
  159.             {
  160.                 buffer = null;
  161.                 expIndex = 0;
  162.             }
  163.         } else if (swapOrder != 0) {
  164.             int order = swapOrder << 16;
  165.             swapOrder = 0;
  166.             return order;
  167.         }
  168.         char ch = text.next();
  169.         if (ch == Normalizer.DONE) {
  170.             return NULLORDER;
  171.         }
  172.  
  173.         int value = ordering.getUnicodeOrder(ch);
  174.         if (value == RuleBasedCollator.UNMAPPED)
  175.         {
  176.             swapOrder = ch;
  177.             return UNMAPPEDCHARVALUE;
  178.         }
  179.         else if (value < RuleBasedCollator.CHARINDEX)
  180.         {
  181.             return strengthOrder(value);
  182.         }
  183.         // contract characters
  184.         else if (value >= RuleBasedCollator.CONTRACTCHARINDEX)
  185.         {
  186.             return strengthOrder(nextContractChar(ch));
  187.         }
  188.         else if (value >= RuleBasedCollator.EXPANDCHARINDEX)
  189.         {
  190.             buffer = ordering.getExpandValueList(ch);
  191.             expIndex = 0;
  192.             return strengthOrder(buffer[expIndex++]);
  193.         }
  194.         return NULLORDER;
  195.     }
  196.     /**
  197.      * Get the primary order of a collation order.
  198.      * @param order the collation order
  199.      * @return the primary order of a collation order.
  200.      */
  201.     public final static int primaryOrder(int order)
  202.     {
  203.         order &= RuleBasedCollator.PRIMARYORDERMASK;
  204.         return (order >>> RuleBasedCollator.PRIMARYORDERSHIFT);
  205.     }
  206.     /**
  207.      * Get the secondary order of a collation order.
  208.      * @param order the collation order
  209.      * @return the secondary order of a collation order.
  210.      */
  211.     public final static short secondaryOrder(int order)
  212.     {
  213.         order = order & RuleBasedCollator.SECONDARYORDERMASK;
  214.         return ((short)(order >> RuleBasedCollator.SECONDARYORDERSHIFT));
  215.     }
  216.     /**
  217.      * Get the tertiary order of a collation order.
  218.      * @param order the collation order
  219.      * @return the tertiary order of a collation order.
  220.      */
  221.     public final static short tertiaryOrder(int order)
  222.     {
  223.         return ((short)(order &= RuleBasedCollator.TERTIARYORDERMASK));
  224.     }
  225.  
  226.     /**
  227.      *  Get the comparison order in the desired strength.  Ignore the other
  228.      *  differences.
  229.      *  @param order The order value
  230.      */
  231.     final int strengthOrder(int order)
  232.     {
  233.         int s = ordering.getStrength();
  234.         if (s == Collator.PRIMARY)
  235.         {
  236.             order &= RuleBasedCollator.PRIMARYDIFFERENCEONLY;
  237.         } else if (s == Collator.SECONDARY)
  238.         {
  239.             order &= RuleBasedCollator.SECONDARYDIFFERENCEONLY;
  240.         }
  241.         return order;
  242.     }
  243.  
  244.     /**
  245.       * Sets the position within the source text.
  246.       *
  247.       * @param newOffset The new offset relative to the start of the text.
  248.       */
  249.     void setOffset(int newOffset)
  250.     {
  251.         if (text != null)
  252.             text.setOffset(newOffset);
  253.     }
  254.  
  255.     /**
  256.       * Gets the offset of the current character in the source text.
  257.       * That is, the next call to next() will return the Collation element
  258.       * for this character (possibly including more than one character,
  259.       * if required by the language).
  260.       *
  261.       * @return the returned ofset.
  262.       */
  263.     int getOffset()
  264.     {
  265.         return (text != null) ? text.getOffset() : 0;
  266.     }
  267.  
  268.     /**
  269.       * Get the ordering priority of the previous collation element in the string.
  270.       * @return the previous element's ordering.  Returns NULLORDER if
  271.       * the beginning of string is reached.
  272.       */
  273.     int previous()
  274.     {
  275.         if (buffer != null && expIndex > 0) {
  276.             return buffer[--expIndex];
  277.         } else {
  278.             char ch = text.previous();
  279.             if (ch == Normalizer.DONE) {
  280.                 return NULLORDER;
  281.             }
  282.  
  283.             int value = ordering.getUnicodeOrder(ch);
  284.  
  285.             if (value == RuleBasedCollator.UNMAPPED)
  286.             {
  287.                 swapOrder = ch;
  288.                 return UNMAPPEDCHARVALUE;
  289.             }
  290.             else if (value < RuleBasedCollator.CHARINDEX)
  291.             {
  292.                 return strengthOrder(value);
  293.             }
  294.             // contract characters
  295.             else if (value >= RuleBasedCollator.CONTRACTCHARINDEX)
  296.             {
  297.                 // TODO: This is broken.  When going backwards, we need to
  298.                 // see if this character is the LAST character in a contraction
  299.                 // sequence, which means we need a new mapping table in the
  300.                 // RuleBasedCollator object
  301.                 return strengthOrder(nextContractChar(ch));
  302.             }
  303.             else if (value >= RuleBasedCollator.EXPANDCHARINDEX)
  304.             {
  305.                 buffer = ordering.getExpandValueList(ch);
  306.                 expIndex = buffer.length;
  307.                 return strengthOrder(buffer[--expIndex]);
  308.             }
  309.             return NULLORDER;
  310.         }
  311.     }
  312.  
  313.     /**
  314.       * Return the maximum length of any expansion sequences that end
  315.       * with the specified comparison order.
  316.       * @param order a collation order returned by previous or next.
  317.       * @return the maximum length of any expansion seuences ending
  318.       *         with the specified order.
  319.       */
  320.     int getMaxExpansion(int order)
  321.     {
  322.         return 2;   // TODO: implement me
  323.     }
  324.  
  325.     //============================================================
  326.     // Package-visible methods that should eventually be made public
  327.     //============================================================
  328.  
  329.     /**
  330.      * Set a new string over which to iterate.
  331.      *
  332.      * @param str the new source text.
  333.      */
  334.     void setText(String source)
  335.     {
  336.         buffer = null;
  337.         swapOrder = 0;
  338.         if (text == null) {
  339.             text = new Normalizer(source, ordering.getDecomposition());
  340.         } else {
  341.             text.setDecomposition(ordering.getDecomposition());
  342.             text.setText(source);
  343.         }
  344.     }
  345.  
  346.     /**
  347.      * Set a new string over which to iterate.
  348.      *
  349.      * @param str the new source text.
  350.      */
  351.     void setText(CharacterIterator source)
  352.     {
  353.         buffer = null;
  354.         swapOrder = 0;
  355.         if (text == null) {
  356.             text = new Normalizer(source, ordering.getDecomposition());
  357.         } else {
  358.             text.setDecomposition(ordering.getDecomposition());
  359.             text.setText(source);
  360.         }
  361.     }
  362.  
  363.     //============================================================
  364.     // privates
  365.     //============================================================
  366.  
  367.     /**
  368.      *  Check if a comparison order is ignorable.
  369.      *  @return true if a character is ignorable, false otherwise.
  370.      */
  371.     final static boolean isIgnorable(int order)
  372.     {
  373.         return ((primaryOrder(order) == 0) ? true : false);
  374.     }
  375.  
  376.     private int getEntry(Vector list, String name) {
  377.         for (int i = 0; i < list.size(); i++) {
  378.             EntryPair pair = (EntryPair)list.elementAt(i);
  379.             if (pair.entryName.equals(name)) {
  380.                 return i;
  381.             }
  382.         }
  383.         return RuleBasedCollator.UNMAPPED;
  384.     }
  385.  
  386.     /**
  387.      * Get the ordering priority of the next contracting character in the
  388.      * string.
  389.      * @param ch the starting character of a contracting character token
  390.      * @return the next contracting character's ordering.  Returns NULLORDER
  391.      * if the end of string is reached.
  392.      */
  393.     private int nextContractChar(char ch)
  394.     {
  395.         EntryPair pair = null;
  396.         Vector list = ordering.getContractValues(ch);
  397.         int intValue = 0;
  398.         key.setLength(0);
  399.         key.append(ch);
  400.         int n = 0;
  401.         if ((n = getEntry(list, key.toString())) != RuleBasedCollator.UNMAPPED) {
  402.             pair = (EntryPair)list.elementAt(n);
  403.             intValue = pair.value;
  404.         }
  405.         while((ch = text.next()) != Normalizer.DONE)
  406.         {
  407.             key.append(ch);
  408.             if ((n = getEntry(list, key.toString())) ==
  409.                      RuleBasedCollator.UNMAPPED) {
  410.                 ch = text.previous();
  411.                 break;
  412.             }
  413.             pair = (EntryPair)list.elementAt(n);
  414.             intValue = pair.value;
  415.         }
  416.         // if contracting char is also an expanding char
  417.         if ((intValue  - RuleBasedCollator.EXPANDCHARINDEX) >= 0)
  418.         {
  419.             buffer = ordering.getExpandValueList
  420.                      (intValue - RuleBasedCollator.EXPANDCHARINDEX);
  421.             expIndex = 0;
  422.             intValue = buffer[expIndex++];
  423.         }
  424.         return intValue;
  425.     }
  426.  
  427.     final static int UNMAPPEDCHARVALUE = 0x7FFF0000;
  428.  
  429.     private Normalizer text = null;
  430.     private int[] buffer = null;
  431.     private int expIndex = 0;
  432.     private StringBuffer key = new StringBuffer(5);
  433.     private int swapOrder = 0;
  434.     private RuleBasedCollator ordering;
  435. }
  436.