| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.lucene.analysis.hunspell; |
| |
| import java.util.List; |
| import org.apache.lucene.util.IntsRef; |
| |
| class CompoundRule { |
| private final char[] data; |
| private final Dictionary dictionary; |
| |
| CompoundRule(String rule, Dictionary dictionary) { |
| this.dictionary = dictionary; |
| StringBuilder parsedFlags = new StringBuilder(); |
| int pos = 0; |
| while (pos < rule.length()) { |
| int lParen = rule.indexOf("(", pos); |
| if (lParen < 0) { |
| parsedFlags.append(dictionary.flagParsingStrategy.parseFlags(rule.substring(pos))); |
| break; |
| } |
| |
| parsedFlags.append(dictionary.flagParsingStrategy.parseFlags(rule.substring(pos, lParen))); |
| int rParen = rule.indexOf(')', lParen + 1); |
| if (rParen < 0) { |
| throw new IllegalArgumentException("Unmatched parentheses: " + rule); |
| } |
| |
| parsedFlags.append( |
| dictionary.flagParsingStrategy.parseFlags(rule.substring(lParen + 1, rParen))); |
| pos = rParen + 1; |
| if (pos < rule.length() && (rule.charAt(pos) == '?' || rule.charAt(pos) == '*')) { |
| parsedFlags.append(rule.charAt(pos++)); |
| } |
| } |
| data = parsedFlags.toString().toCharArray(); |
| } |
| |
| boolean mayMatch(List<IntsRef> words) { |
| return match(words, 0, 0, false); |
| } |
| |
| boolean fullyMatches(List<IntsRef> words) { |
| return match(words, 0, 0, true); |
| } |
| |
| private boolean match(List<IntsRef> words, int patternIndex, int wordIndex, boolean fully) { |
| if (patternIndex >= data.length) { |
| return wordIndex >= words.size(); |
| } |
| if (wordIndex >= words.size() && !fully) { |
| return true; |
| } |
| |
| char flag = data[patternIndex]; |
| if (patternIndex < data.length - 1 && data[patternIndex + 1] == '*') { |
| int startWI = wordIndex; |
| while (wordIndex < words.size() && dictionary.hasFlag(words.get(wordIndex), flag)) { |
| wordIndex++; |
| } |
| |
| while (wordIndex >= startWI) { |
| if (match(words, patternIndex + 2, wordIndex, fully)) { |
| return true; |
| } |
| |
| wordIndex--; |
| } |
| return false; |
| } |
| |
| boolean currentWordMatches = |
| wordIndex < words.size() && dictionary.hasFlag(words.get(wordIndex), flag); |
| |
| if (patternIndex < data.length - 1 && data[patternIndex + 1] == '?') { |
| if (currentWordMatches && match(words, patternIndex + 2, wordIndex + 1, fully)) { |
| return true; |
| } |
| return match(words, patternIndex + 2, wordIndex, fully); |
| } |
| |
| return currentWordMatches && match(words, patternIndex + 1, wordIndex + 1, fully); |
| } |
| |
| @Override |
| public String toString() { |
| return new String(data); |
| } |
| } |