Home | History | Annotate | Download | only in text
      1 /*
      2  *******************************************************************************
      3  * Copyright (C) 1996-2015, International Business Machines Corporation and    *
      4  * others. All Rights Reserved.                                                *
      5  *******************************************************************************
      6  */
      7 
      8 package com.ibm.icu.text;
      9 
     10 import java.text.CharacterIterator;
     11 
     12 /**
     13  * <tt>SearchIterator</tt> is an abstract base class that provides
     14  * methods to search for a pattern within a text string. Instances of
     15  * <tt>SearchIterator</tt> maintain a current position and scan over the
     16  * target text, returning the indices the pattern is matched and the length
     17  * of each match.
     18  * <p>
     19  * <tt>SearchIterator</tt> defines a protocol for text searching.
     20  * Subclasses provide concrete implementations of various search algorithms.
     21  * For example, <tt>StringSearch</tt> implements language-sensitive pattern
     22  * matching based on the comparison rules defined in a
     23  * <tt>RuleBasedCollator</tt> object.
     24  * <p>
     25  * Other options for searching include using a BreakIterator to restrict
     26  * the points at which matches are detected.
     27  * <p>
     28  * <tt>SearchIterator</tt> provides an API that is similar to that of
     29  * other text iteration classes such as <tt>BreakIterator</tt>. Using
     30  * this class, it is easy to scan through text looking for all occurrences of
     31  * a given pattern. The following example uses a <tt>StringSearch</tt>
     32  * object to find all instances of "fox" in the target string. Any other
     33  * subclass of <tt>SearchIterator</tt> can be used in an identical
     34  * manner.
     35  * <pre><code>
     36  * String target = "The quick brown fox jumped over the lazy fox";
     37  * String pattern = "fox";
     38  * SearchIterator iter = new StringSearch(pattern, target);
     39  * for (int pos = iter.first(); pos != SearchIterator.DONE;
     40  *         pos = iter.next()) {
     41  *     System.out.println("Found match at " + pos +
     42  *             ", length is " + iter.getMatchLength());
     43  * }
     44  * </code></pre>
     45  *
     46  * @author Laura Werner, synwee
     47  * @stable ICU 2.0
     48  * @see BreakIterator
     49  * @see RuleBasedCollator
     50  */
     51 public abstract class SearchIterator
     52 {
     53     /**
     54      * The BreakIterator to define the boundaries of a logical match.
     55      * This value can be a null.
     56      * See class documentation for more information.
     57      * @see #setBreakIterator(BreakIterator)
     58      * @see #getBreakIterator
     59      * @see BreakIterator
     60      * @stable ICU 2.0
     61      */
     62     protected BreakIterator breakIterator;
     63 
     64     /**
     65      * Target text for searching.
     66      * @see #setTarget(CharacterIterator)
     67      * @see #getTarget
     68      * @stable ICU 2.0
     69      */
     70     protected CharacterIterator targetText;
     71     /**
     72      * Length of the most current match in target text.
     73      * Value 0 is the default value.
     74      * @see #setMatchLength
     75      * @see #getMatchLength
     76      * @stable ICU 2.0
     77      */
     78     protected int matchLength;
     79 
     80     /**
     81      * Java port of ICU4C struct USearch (usrchimp.h)
     82      *
     83      * Note:
     84      *
     85      *  ICU4J already exposed some protected members such as
     86      * targetText, breakIterator and matchedLength as a part of stable
     87      * APIs. In ICU4C, they are exposed through USearch struct,
     88      * although USearch struct itself is internal API.
     89      *
     90      *  This class was created for making ICU4J code parallel to
     91      * ICU4C implementation. ICU4J implementation access member
     92      * fields like C struct (e.g. search_.isOverlap_) mostly, except
     93      * fields already exposed as protected member (e.g. search_.text()).
     94      *
     95      */
     96     final class Search {
     97 
     98         CharacterIterator text() {
     99             return SearchIterator.this.targetText;
    100         }
    101 
    102         void setTarget(CharacterIterator text) {
    103             SearchIterator.this.targetText = text;
    104         }
    105 
    106         /** Flag to indicate if overlapping search is to be done.
    107             E.g. looking for "aa" in "aaa" will yield matches at offset 0 and 1. */
    108         boolean isOverlap_;
    109 
    110         boolean isCanonicalMatch_;
    111 
    112         ElementComparisonType elementComparisonType_;
    113 
    114         BreakIterator internalBreakIter_;
    115 
    116         BreakIterator breakIter() {
    117             return SearchIterator.this.breakIterator;
    118         }
    119 
    120         void setBreakIter(BreakIterator breakIter) {
    121             SearchIterator.this.breakIterator = breakIter;
    122         }
    123 
    124         int matchedIndex_;
    125 
    126         int matchedLength() {
    127             return SearchIterator.this.matchLength;
    128         }
    129 
    130         void setMatchedLength(int matchedLength) {
    131             SearchIterator.this.matchLength = matchedLength;
    132         }
    133 
    134         /** Flag indicates if we are doing a forwards search */
    135         boolean isForwardSearching_;
    136 
    137         /** Flag indicates if we are at the start of a string search.
    138             This indicates that we are in forward search and at the start of m_text. */
    139         boolean reset_;
    140 
    141         // Convenient methods for accessing begin/end index of the
    142         // target text. These are ICU4J only and are not data fields.
    143         int beginIndex() {
    144             if (targetText == null) {
    145                 return 0;
    146             }
    147             return targetText.getBeginIndex();
    148         }
    149 
    150         int endIndex() {
    151             if (targetText == null) {
    152                 return 0;
    153             }
    154             return targetText.getEndIndex();
    155         }
    156     }
    157 
    158     Search search_ = new Search();
    159 
    160     // public data members -------------------------------------------------
    161 
    162     /**
    163      * DONE is returned by previous() and next() after all valid matches have
    164      * been returned, and by first() and last() if there are no matches at all.
    165      * @see #previous
    166      * @see #next
    167      * @stable ICU 2.0
    168      */
    169     public static final int DONE = -1;
    170 
    171     // public methods -----------------------------------------------------
    172 
    173     // public setters -----------------------------------------------------
    174 
    175     /**
    176      * <p>
    177      * Sets the position in the target text at which the next search will start.
    178      * This method clears any previous match.
    179      * </p>
    180      * @param position position from which to start the next search
    181      * @exception IndexOutOfBoundsException thrown if argument position is out
    182      *            of the target text range.
    183      * @see #getIndex
    184      * @stable ICU 2.8
    185      */
    186     public void setIndex(int position) {
    187         if (position < search_.beginIndex()
    188             || position > search_.endIndex()) {
    189             throw new IndexOutOfBoundsException(
    190                 "setIndex(int) expected position to be between " +
    191                 search_.beginIndex() + " and " + search_.endIndex());
    192         }
    193         search_.reset_ = false;
    194         search_.setMatchedLength(0);
    195         search_.matchedIndex_ = DONE;
    196     }
    197 
    198     /**
    199      * Determines whether overlapping matches are returned. See the class
    200      * documentation for more information about overlapping matches.
    201      * <p>
    202      * The default setting of this property is false
    203      *
    204      * @param allowOverlap flag indicator if overlapping matches are allowed
    205      * @see #isOverlapping
    206      * @stable ICU 2.8
    207      */
    208     public void setOverlapping(boolean allowOverlap) {
    209         search_.isOverlap_ = allowOverlap;
    210     }
    211 
    212     /**
    213      * Set the BreakIterator that will be used to restrict the points
    214      * at which matches are detected.
    215      *
    216      * @param breakiter A BreakIterator that will be used to restrict the
    217      *                points at which matches are detected. If a match is
    218      *                found, but the match's start or end index is not a
    219      *                boundary as determined by the {@link BreakIterator},
    220      *                the match will be rejected and another will be searched
    221      *                for. If this parameter is <tt>null</tt>, no break
    222      *                detection is attempted.
    223      * @see BreakIterator
    224      * @stable ICU 2.0
    225      */
    226     public void setBreakIterator(BreakIterator breakiter) {
    227         search_.setBreakIter(breakiter);
    228         if (search_.breakIter() != null) {
    229             // Create a clone of CharacterItearator, so it won't
    230             // affect the position currently held by search_.text()
    231             if (search_.text() != null) {
    232                 search_.breakIter().setText((CharacterIterator)search_.text().clone());
    233             }
    234         }
    235     }
    236 
    237     /**
    238      * Set the target text to be searched. Text iteration will then begin at
    239      * the start of the text string. This method is useful if you want to
    240      * reuse an iterator to search within a different body of text.
    241      *
    242      * @param text new text iterator to look for match,
    243      * @exception IllegalArgumentException thrown when text is null or has
    244      *               0 length
    245      * @see #getTarget
    246      * @stable ICU 2.4
    247      */
    248     public void setTarget(CharacterIterator text)
    249     {
    250         if (text == null || text.getEndIndex() == text.getIndex()) {
    251             throw new IllegalArgumentException("Illegal null or empty text");
    252         }
    253 
    254         text.setIndex(text.getBeginIndex());
    255         search_.setTarget(text);
    256         search_.matchedIndex_ = DONE;
    257         search_.setMatchedLength(0);
    258         search_.reset_ = true;
    259         search_.isForwardSearching_ = true;
    260         if (search_.breakIter() != null) {
    261             // Create a clone of CharacterItearator, so it won't
    262             // affect the position currently held by search_.text()
    263             search_.breakIter().setText((CharacterIterator)text.clone());
    264         }
    265         if (search_.internalBreakIter_ != null) {
    266             search_.internalBreakIter_.setText((CharacterIterator)text.clone());
    267         }
    268     }
    269 
    270     //TODO: We may add APIs below to match ICU4C APIs
    271     // setCanonicalMatch
    272 
    273     // public getters ----------------------------------------------------
    274 
    275     /**
    276     * Returns the index to the match in the text string that was searched.
    277     * This call returns a valid result only after a successful call to
    278     * {@link #first}, {@link #next}, {@link #previous}, or {@link #last}.
    279     * Just after construction, or after a searching method returns
    280     * {@link #DONE}, this method will return {@link #DONE}.
    281     * <p>
    282     * Use {@link #getMatchLength} to get the matched string length.
    283     *
    284     * @return index of a substring within the text string that is being
    285     *         searched.
    286     * @see #first
    287     * @see #next
    288     * @see #previous
    289     * @see #last
    290     * @stable ICU 2.0
    291     */
    292     public int getMatchStart() {
    293         return search_.matchedIndex_;
    294     }
    295 
    296     /**
    297      * Return the current index in the text being searched.
    298      * If the iteration has gone past the end of the text
    299      * (or past the beginning for a backwards search), {@link #DONE}
    300      * is returned.
    301      *
    302      * @return current index in the text being searched.
    303      * @stable ICU 2.8
    304      */
    305     public abstract int getIndex();
    306 
    307     /**
    308      * Returns the length of text in the string which matches the search
    309      * pattern. This call returns a valid result only after a successful call
    310      * to {@link #first}, {@link #next}, {@link #previous}, or {@link #last}.
    311      * Just after construction, or after a searching method returns
    312      * {@link #DONE}, this method will return 0.
    313      *
    314      * @return The length of the match in the target text, or 0 if there
    315      *         is no match currently.
    316      * @see #first
    317      * @see #next
    318      * @see #previous
    319      * @see #last
    320      * @stable ICU 2.0
    321      */
    322     public int getMatchLength() {
    323         return search_.matchedLength();
    324     }
    325 
    326     /**
    327      * Returns the BreakIterator that is used to restrict the indexes at which
    328      * matches are detected. This will be the same object that was passed to
    329      * the constructor or to {@link #setBreakIterator}.
    330      * If the {@link BreakIterator} has not been set, <tt>null</tt> will be returned.
    331      * See {@link #setBreakIterator} for more information.
    332      *
    333      * @return the BreakIterator set to restrict logic matches
    334      * @see #setBreakIterator
    335      * @see BreakIterator
    336      * @stable ICU 2.0
    337      */
    338     public BreakIterator getBreakIterator() {
    339         return search_.breakIter();
    340     }
    341 
    342     /**
    343      * Return the string text to be searched.
    344      * @return text string to be searched.
    345      * @stable ICU 2.0
    346      */
    347     public CharacterIterator getTarget() {
    348         return search_.text();
    349     }
    350 
    351     /**
    352      * Returns the text that was matched by the most recent call to
    353      * {@link #first}, {@link #next}, {@link #previous}, or {@link #last}.
    354      * If the iterator is not pointing at a valid match (e.g. just after
    355      * construction or after {@link #DONE} has been returned,
    356      * returns an empty string.
    357      *
    358      * @return  the substring in the target test of the most recent match,
    359      *          or null if there is no match currently.
    360      * @see #first
    361      * @see #next
    362      * @see #previous
    363      * @see #last
    364      * @stable ICU 2.0
    365      */
    366     public String getMatchedText() {
    367         if (search_.matchedLength() > 0) {
    368             int limit = search_.matchedIndex_ + search_.matchedLength();
    369             StringBuilder result = new StringBuilder(search_.matchedLength());
    370             CharacterIterator it = search_.text();
    371             it.setIndex(search_.matchedIndex_);
    372             while (it.getIndex() < limit) {
    373                 result.append(it.current());
    374                 it.next();
    375             }
    376             it.setIndex(search_.matchedIndex_);
    377             return result.toString();
    378         }
    379         return null;
    380     }
    381 
    382     // miscellaneous public methods -----------------------------------------
    383 
    384     /**
    385      * Returns the index of the next point at which the text matches the
    386      * search pattern, starting from the current position
    387      * The iterator is adjusted so that its current index (as returned by
    388      * {@link #getIndex}) is the match position if one was found.
    389      * If a match is not found, {@link #DONE} will be returned and
    390      * the iterator will be adjusted to a position after the end of the text
    391      * string.
    392      *
    393      * @return The index of the next match after the current position,
    394      *          or {@link #DONE} if there are no more matches.
    395      * @see #getIndex
    396      * @stable ICU 2.0
    397      */
    398     public int next() {
    399         int index = getIndex(); // offset = getOffset() in ICU4C
    400         int matchindex = search_.matchedIndex_;
    401         int matchlength = search_.matchedLength();
    402         search_.reset_ = false;
    403         if (search_.isForwardSearching_) {
    404             int endIdx = search_.endIndex();
    405             if (index == endIdx || matchindex == endIdx ||
    406                     (matchindex != DONE &&
    407                     matchindex + matchlength >= endIdx)) {
    408                 setMatchNotFound();
    409                 return DONE;
    410             }
    411         } else {
    412             // switching direction.
    413             // if matchedIndex == DONE, it means that either a
    414             // setIndex (setOffset in C) has been called or that previous ran off the text
    415             // string. the iterator would have been set to offset 0 if a
    416             // match is not found.
    417             search_.isForwardSearching_ = true;
    418             if (search_.matchedIndex_ != DONE) {
    419                 // there's no need to set the collation element iterator
    420                 // the next call to next will set the offset.
    421                 return matchindex;
    422             }
    423         }
    424 
    425         if (matchlength > 0) {
    426             // if matchlength is 0 we are at the start of the iteration
    427             if (search_.isOverlap_) {
    428                 index++;
    429             } else {
    430                 index += matchlength;
    431             }
    432         }
    433 
    434         return handleNext(index);
    435     }
    436 
    437     /**
    438      * Returns the index of the previous point at which the string text
    439      * matches the search pattern, starting at the current position.
    440      * The iterator is adjusted so that its current index (as returned by
    441      * {@link #getIndex}) is the match position if one was found.
    442      * If a match is not found, {@link #DONE} will be returned and
    443      * the iterator will be adjusted to the index {@link #DONE}.
    444      *
    445      * @return The index of the previous match before the current position,
    446      *          or {@link #DONE} if there are no more matches.
    447      * @see #getIndex
    448      * @stable ICU 2.0
    449      */
    450     public int previous() {
    451         int index;  // offset in ICU4C
    452         if (search_.reset_) {
    453             index = search_.endIndex();   // m_search_->textLength in ICU4C
    454             search_.isForwardSearching_ = false;
    455             search_.reset_ = false;
    456             setIndex(index);
    457         } else {
    458             index = getIndex();
    459         }
    460 
    461         int matchindex = search_.matchedIndex_;
    462         if (search_.isForwardSearching_) {
    463             // switching direction.
    464             // if matchedIndex == DONE, it means that either a
    465             // setIndex (setOffset in C) has been called or that next ran off the text
    466             // string. the iterator would have been set to offset textLength if
    467             // a match is not found.
    468             search_.isForwardSearching_ = false;
    469             if (matchindex != DONE) {
    470                 return matchindex;
    471             }
    472         } else {
    473             int startIdx = search_.beginIndex();
    474             if (index == startIdx || matchindex == startIdx) {
    475                 // not enough characters to match
    476                 setMatchNotFound();
    477                 return DONE;
    478             }
    479         }
    480 
    481         if (matchindex != DONE) {
    482             if (search_.isOverlap_) {
    483                 matchindex += search_.matchedLength() - 2;
    484             }
    485 
    486             return handlePrevious(matchindex);
    487         }
    488 
    489         return handlePrevious(index);
    490     }
    491 
    492     /**
    493      * Return true if the overlapping property has been set.
    494      * See {@link #setOverlapping(boolean)} for more information.
    495      *
    496      * @see #setOverlapping
    497      * @return true if the overlapping property has been set, false otherwise
    498      * @stable ICU 2.8
    499      */
    500     public boolean isOverlapping() {
    501         return search_.isOverlap_;
    502     }
    503 
    504     //TODO: We may add APIs below to match ICU4C APIs
    505     // isCanonicalMatch
    506 
    507     /**
    508     * Resets the iteration.
    509     * Search will begin at the start of the text string if a forward
    510     * iteration is initiated before a backwards iteration. Otherwise if a
    511     * backwards iteration is initiated before a forwards iteration, the
    512     * search will begin at the end of the text string.
    513     *
    514     * @stable ICU 2.0
    515     */
    516     public void reset() {
    517         setMatchNotFound();
    518         setIndex(search_.beginIndex());
    519         search_.isOverlap_ = false;
    520         search_.isCanonicalMatch_ = false;
    521         search_.elementComparisonType_ = ElementComparisonType.STANDARD_ELEMENT_COMPARISON;
    522         search_.isForwardSearching_ = true;
    523         search_.reset_ = true;
    524     }
    525 
    526     /**
    527      * Returns the first index at which the string text matches the search
    528      * pattern. The iterator is adjusted so that its current index (as
    529      * returned by {@link #getIndex()}) is the match position if one
    530      *
    531      * was found.
    532      * If a match is not found, {@link #DONE} will be returned and
    533      * the iterator will be adjusted to the index {@link #DONE}.
    534      * @return The character index of the first match, or
    535      *         {@link #DONE} if there are no matches.
    536      *
    537      * @see #getIndex
    538      * @stable ICU 2.0
    539      */
    540     public final int first() {
    541         int startIdx = search_.beginIndex();
    542         setIndex(startIdx);
    543         return handleNext(startIdx);
    544     }
    545 
    546     /**
    547      * Returns the first index equal or greater than <tt>position</tt> at which the
    548      * string text matches the search pattern. The iterator is adjusted so
    549      * that its current index (as returned by {@link #getIndex()}) is the
    550      * match position if one was found.
    551      * If a match is not found, {@link #DONE} will be returned and the
    552      * iterator will be adjusted to the index {@link #DONE}.
    553      *
    554      * @param  position where search if to start from.
    555      * @return The character index of the first match following
    556      *         <tt>position</tt>, or {@link #DONE} if there are no matches.
    557      * @throws IndexOutOfBoundsException    If position is less than or greater
    558      *      than the text range for searching.
    559      * @see #getIndex
    560      * @stable ICU 2.0
    561      */
    562     public final int following(int position) {
    563         setIndex(position);
    564         return handleNext(position);
    565     }
    566 
    567     /**
    568      * Returns the last index in the target text at which it matches the
    569      * search pattern. The iterator is adjusted so that its current index
    570      * (as returned by {@link #getIndex}) is the match position if one was
    571      * found.
    572      * If a match is not found, {@link #DONE} will be returned and
    573      * the iterator will be adjusted to the index {@link #DONE}.
    574      *
    575      * @return The index of the first match, or {@link #DONE} if
    576      *         there are no matches.
    577      * @see #getIndex
    578      * @stable ICU 2.0
    579      */
    580     public final int last() {
    581         int endIdx = search_.endIndex();
    582         setIndex(endIdx);
    583         return handlePrevious(endIdx);
    584     }
    585 
    586     /**
    587      * Returns the first index less than <tt>position</tt> at which the string
    588      * text matches the search pattern. The iterator is adjusted so that its
    589      * current index (as returned by {@link #getIndex}) is the match
    590      * position if one was found. If a match is not found,
    591      * {@link #DONE} will be returned and the iterator will be
    592      * adjusted to the index {@link #DONE}
    593      * <p>
    594      * When the overlapping option ({@link #isOverlapping}) is off, the last index of the
    595      * result match is always less than <tt>position</tt>.
    596      * When the overlapping option is on, the result match may span across
    597      * <tt>position</tt>.
    598      *
    599      * @param  position where search is to start from.
    600      * @return The character index of the first match preceding
    601      *         <tt>position</tt>, or {@link #DONE} if there are
    602      *         no matches.
    603      * @throws IndexOutOfBoundsException If position is less than or greater than
    604      *                                   the text range for searching
    605      * @see #getIndex
    606      * @stable ICU 2.0
    607      */
    608     public final int preceding(int position) {
    609         setIndex(position);
    610         return handlePrevious(position);
    611     }
    612 
    613     // protected constructor ----------------------------------------------
    614 
    615     /**
    616      * Protected constructor for use by subclasses.
    617      * Initializes the iterator with the argument target text for searching
    618      * and sets the BreakIterator.
    619      * See class documentation for more details on the use of the target text
    620      * and {@link BreakIterator}.
    621      *
    622      * @param target The target text to be searched.
    623      * @param breaker A {@link BreakIterator} that is used to determine the
    624      *                boundaries of a logical match. This argument can be null.
    625      * @exception IllegalArgumentException thrown when argument target is null,
    626      *            or of length 0
    627      * @see BreakIterator
    628      * @stable ICU 2.0
    629      */
    630     protected SearchIterator(CharacterIterator target, BreakIterator breaker)
    631     {
    632         if (target == null
    633             || (target.getEndIndex() - target.getBeginIndex()) == 0) {
    634                 throw new IllegalArgumentException(
    635                                    "Illegal argument target. " +
    636                                    " Argument can not be null or of length 0");
    637         }
    638 
    639         search_.setTarget(target);
    640         search_.setBreakIter(breaker);
    641         if (search_.breakIter() != null) {
    642             search_.breakIter().setText((CharacterIterator)target.clone());
    643         }
    644         search_.isOverlap_ = false;
    645         search_.isCanonicalMatch_ = false;
    646         search_.elementComparisonType_ = ElementComparisonType.STANDARD_ELEMENT_COMPARISON;
    647         search_.isForwardSearching_ = true;
    648         search_.reset_ = true;
    649         search_.matchedIndex_ = DONE;
    650         search_.setMatchedLength(0);
    651     }
    652 
    653     // protected methods --------------------------------------------------
    654 
    655 
    656     /**
    657      * Sets the length of the most recent match in the target text.
    658      * Subclasses' handleNext() and handlePrevious() methods should call this
    659      * after they find a match in the target text.
    660      *
    661      * @param length new length to set
    662      * @see #handleNext
    663      * @see #handlePrevious
    664      * @stable ICU 2.0
    665      */
    666     protected void setMatchLength(int length)
    667     {
    668         search_.setMatchedLength(length);
    669     }
    670 
    671     /**
    672      * Abstract method which subclasses override to provide the mechanism
    673      * for finding the next match in the target text. This allows different
    674      * subclasses to provide different search algorithms.
    675      * <p>
    676      * If a match is found, the implementation should return the index at
    677      * which the match starts and should call
    678      * {@link #setMatchLength} with the number of characters
    679      * in the target text that make up the match. If no match is found, the
    680      * method should return {@link #DONE}.
    681      *
    682      * @param start The index in the target text at which the search
    683      *              should start.
    684      * @return index at which the match starts, else if match is not found
    685      *         {@link #DONE} is returned
    686      * @see #setMatchLength
    687      * @stable ICU 2.0
    688      */
    689     protected abstract int handleNext(int start);
    690 
    691     /**
    692      * Abstract method which subclasses override to provide the mechanism for
    693      * finding the previous match in the target text. This allows different
    694      * subclasses to provide different search algorithms.
    695      * <p>
    696      * If a match is found, the implementation should return the index at
    697      * which the match starts and should call
    698      * {@link #setMatchLength} with the number of characters
    699      * in the target text that make up the match. If no match is found, the
    700      * method should return {@link #DONE}.
    701      *
    702      * @param startAt   The index in the target text at which the search
    703      *                  should start.
    704      * @return index at which the match starts, else if match is not found
    705      *         {@link #DONE} is returned
    706      * @see #setMatchLength
    707      * @stable ICU 2.0
    708      */
    709     protected abstract int handlePrevious(int startAt);
    710 
    711     /**
    712      * @internal
    713      * @deprecated This API is ICU internal only.
    714      */
    715     @Deprecated
    716     //TODO: This protected method is @stable 2.0 in ICU4C
    717     protected void setMatchNotFound() {
    718         search_.matchedIndex_ = DONE;
    719         search_.setMatchedLength(0);
    720     }
    721 
    722     /**
    723      * Option to control how collation elements are compared.
    724      * The default value will be {@link #STANDARD_ELEMENT_COMPARISON}.
    725      * <p>
    726      * PATTERN_BASE_WEIGHT_IS_WILDCARD supports "asymmetric search" as described in
    727      * <a href="http://www.unicode.org/reports/tr10/#Asymmetric_Search">
    728      * UTS #10 Unicode Collation Algorithm</a>, while ANY_BASE_WEIGHT_IS_WILDCARD
    729      * supports a related option in which "unmarked" characters in either the
    730      * pattern or the searched text are treated as wildcards that match marked or
    731      * unmarked versions of the same character.
    732      *
    733      * @see #setElementComparisonType(ElementComparisonType)
    734      * @see #getElementComparisonType()
    735      * @stable ICU 53
    736      */
    737     public enum ElementComparisonType {
    738         /**
    739          * Standard collation element comparison at the specified collator strength.
    740          *
    741          * @stable ICU 53
    742          */
    743         STANDARD_ELEMENT_COMPARISON,
    744         /**
    745          * Collation element comparison is modified to effectively provide behavior
    746          * between the specified strength and strength - 1.
    747          * <p>
    748          * Collation elements in the pattern that have the base weight for the specified
    749          * strength are treated as "wildcards" that match an element with any other
    750          * weight at that collation level in the searched text. For example, with a
    751          * secondary-strength English collator, a plain 'e' in the pattern will match
    752          * a plain e or an e with any diacritic in the searched text, but an e with
    753          * diacritic in the pattern will only match an e with the same diacritic in
    754          * the searched text.
    755          *
    756          * @stable ICU 53
    757          */
    758         PATTERN_BASE_WEIGHT_IS_WILDCARD,
    759 
    760         /**
    761          * Collation element comparison is modified to effectively provide behavior
    762          * between the specified strength and strength - 1.
    763          * <p>
    764          * Collation elements in either the pattern or the searched text that have the
    765          * base weight for the specified strength are treated as "wildcards" that match
    766          * an element with any other weight at that collation level. For example, with
    767          * a secondary-strength English collator, a plain 'e' in the pattern will match
    768          * a plain e or an e with any diacritic in the searched text, but an e with
    769          * diacritic in the pattern will only match an e with the same diacritic or a
    770          * plain e in the searched text.
    771          *
    772          * @stable ICU 53
    773          */
    774         ANY_BASE_WEIGHT_IS_WILDCARD
    775     }
    776 
    777     /**
    778      * Sets the collation element comparison type.
    779      * <p>
    780      * The default comparison type is {@link ElementComparisonType#STANDARD_ELEMENT_COMPARISON}.
    781      *
    782      * @see ElementComparisonType
    783      * @see #getElementComparisonType()
    784      * @stable ICU 53
    785      */
    786     public void setElementComparisonType(ElementComparisonType type) {
    787         search_.elementComparisonType_ = type;
    788     }
    789 
    790     /**
    791      * Returns the collation element comparison type.
    792      *
    793      * @see ElementComparisonType
    794      * @see #setElementComparisonType(ElementComparisonType)
    795      * @stable ICU 53
    796      */
    797     public ElementComparisonType getElementComparisonType() {
    798         return search_.elementComparisonType_;
    799     }
    800 }
    801