PyLucene 3.4.0-1 import
[pylucene.git] / lucene-java-3.4.0 / lucene / src / java / org / apache / lucene / search / WildcardTermEnum.java
1 package org.apache.lucene.search;
2
3 /**
4  * Licensed to the Apache Software Foundation (ASF) under one or more
5  * contributor license agreements.  See the NOTICE file distributed with
6  * this work for additional information regarding copyright ownership.
7  * The ASF licenses this file to You under the Apache License, Version 2.0
8  * (the "License"); you may not use this file except in compliance with
9  * the License.  You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 import java.io.IOException;
21
22 import org.apache.lucene.index.IndexReader;
23 import org.apache.lucene.index.Term;
24
25 /**
26  * Subclass of FilteredTermEnum for enumerating all terms that match the
27  * specified wildcard filter term.
28  * <p>
29  * Term enumerations are always ordered by Term.compareTo().  Each term in
30  * the enumeration is greater than all that precede it.
31  */
32 public class WildcardTermEnum extends FilteredTermEnum {
33   final Term searchTerm;
34   final String field;
35   final String text;
36   final String pre;
37   final int preLen;
38   boolean endEnum = false;
39
40   /**
41    * Creates a new <code>WildcardTermEnum</code>.
42    * <p>
43    * After calling the constructor the enumeration is already pointing to the first 
44    * valid term if such a term exists.
45    */
46   public WildcardTermEnum(IndexReader reader, Term term) throws IOException {
47     super();
48     searchTerm = term;
49     field = searchTerm.field();
50     final String searchTermText = searchTerm.text();
51
52     final int sidx = searchTermText.indexOf(WILDCARD_STRING);
53     final int cidx = searchTermText.indexOf(WILDCARD_CHAR);
54     int idx = sidx;
55     if (idx == -1) {
56       idx = cidx;
57     }
58     else if (cidx >= 0) {
59       idx = Math.min(idx, cidx);
60     }
61     pre = idx != -1?searchTerm.text().substring(0,idx): "";
62
63     preLen = pre.length();
64     text = searchTermText.substring(preLen);
65     setEnum(reader.terms(new Term(searchTerm.field(), pre)));
66   }
67
68   @Override
69   protected final boolean termCompare(Term term) {
70     if (field == term.field()) {
71       String searchText = term.text();
72       if (searchText.startsWith(pre)) {
73         return wildcardEquals(text, 0, searchText, preLen);
74       }
75     }
76     endEnum = true;
77     return false;
78   }
79
80   @Override
81   public float difference() {
82     return 1.0f;
83   }
84
85   @Override
86   public final boolean endEnum() {
87     return endEnum;
88   }
89
90   /********************************************
91    * String equality with support for wildcards
92    ********************************************/
93
94   public static final char WILDCARD_STRING = '*';
95   public static final char WILDCARD_CHAR = '?';
96
97   /**
98    * Determines if a word matches a wildcard pattern.
99    * <small>Work released by Granta Design Ltd after originally being done on
100    * company time.</small>
101    */
102   public static final boolean wildcardEquals(String pattern, int patternIdx,
103     String string, int stringIdx)
104   {
105     int p = patternIdx;
106     
107     for (int s = stringIdx; ; ++p, ++s)
108       {
109         // End of string yet?
110         boolean sEnd = (s >= string.length());
111         // End of pattern yet?
112         boolean pEnd = (p >= pattern.length());
113
114         // If we're looking at the end of the string...
115         if (sEnd)
116         {
117           // Assume the only thing left on the pattern is/are wildcards
118           boolean justWildcardsLeft = true;
119
120           // Current wildcard position
121           int wildcardSearchPos = p;
122           // While we haven't found the end of the pattern,
123           // and haven't encountered any non-wildcard characters
124           while (wildcardSearchPos < pattern.length() && justWildcardsLeft)
125           {
126             // Check the character at the current position
127             char wildchar = pattern.charAt(wildcardSearchPos);
128             
129             // If it's not a wildcard character, then there is more
130             // pattern information after this/these wildcards.
131             if (wildchar != WILDCARD_CHAR && wildchar != WILDCARD_STRING)
132             {
133               justWildcardsLeft = false;
134             }
135             else
136             {
137               // to prevent "cat" matches "ca??"
138               if (wildchar == WILDCARD_CHAR) {
139                 return false;
140               }
141               
142               // Look at the next character
143               wildcardSearchPos++;
144             }
145           }
146
147           // This was a prefix wildcard search, and we've matched, so
148           // return true.
149           if (justWildcardsLeft)
150           {
151             return true;
152           }
153         }
154
155         // If we've gone past the end of the string, or the pattern,
156         // return false.
157         if (sEnd || pEnd)
158         {
159           break;
160         }
161
162         // Match a single character, so continue.
163         if (pattern.charAt(p) == WILDCARD_CHAR)
164         {
165           continue;
166         }
167
168         //
169         if (pattern.charAt(p) == WILDCARD_STRING)
170         {
171           // Look at the character beyond the '*' characters.
172           while (p < pattern.length() && pattern.charAt(p) == WILDCARD_STRING)
173             ++p;
174           // Examine the string, starting at the last character.
175           for (int i = string.length(); i >= s; --i)
176           {
177             if (wildcardEquals(pattern, p, string, i))
178             {
179               return true;
180             }
181           }
182           break;
183         }
184         if (pattern.charAt(p) != string.charAt(s))
185         {
186           break;
187         }
188       }
189       return false;
190   }
191 }