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 
text()98         CharacterIterator text() {
99             return SearchIterator.this.targetText;
100         }
101 
setTarget(CharacterIterator text)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 
breakIter()116         BreakIterator breakIter() {
117             return SearchIterator.this.breakIterator;
118         }
119 
setBreakIter(BreakIterator breakIter)120         void setBreakIter(BreakIterator breakIter) {
121             SearchIterator.this.breakIterator = breakIter;
122         }
123 
124         int matchedIndex_;
125 
matchedLength()126         int matchedLength() {
127             return SearchIterator.this.matchLength;
128         }
129 
setMatchedLength(int matchedLength)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.
beginIndex()143         int beginIndex() {
144             if (targetText == null) {
145                 return 0;
146             }
147             return targetText.getBeginIndex();
148         }
149 
endIndex()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      */
setIndex(int position)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      */
setOverlapping(boolean allowOverlap)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      */
setBreakIterator(BreakIterator breakiter)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      */
setTarget(CharacterIterator text)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     */
getMatchStart()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      */
getIndex()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      */
getMatchLength()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      */
getBreakIterator()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      */
getTarget()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      */
getMatchedText()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      */
next()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      */
previous()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      */
isOverlapping()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     */
reset()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      */
first()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      */
following(int position)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      */
last()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      */
preceding(int position)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      */
SearchIterator(CharacterIterator target, BreakIterator breaker)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      */
setMatchLength(int length)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      */
handleNext(int start)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      */
handlePrevious(int startAt)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
setMatchNotFound()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      */
setElementComparisonType(ElementComparisonType type)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      */
getElementComparisonType()797     public ElementComparisonType getElementComparisonType() {
798         return search_.elementComparisonType_;
799     }
800 }
801