Added missing override annotations. Added final modifier to Interval member variables. Updated documentation for ignoreCase (issue #33) and moved the ignore methods to the top of the builder to reflect their preferred calling order.
This commit is contained in:
parent
89e7efab72
commit
5edf6d8126
@ -2,8 +2,8 @@ package org.ahocorasick.interval;
|
|||||||
|
|
||||||
public class Interval implements Intervalable {
|
public class Interval implements Intervalable {
|
||||||
|
|
||||||
private int start;
|
private final int start;
|
||||||
private int end;
|
private final int end;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an interval with a start and end position.
|
* Constructs an interval with a start and end position.
|
||||||
@ -21,6 +21,7 @@ public class Interval implements Intervalable {
|
|||||||
*
|
*
|
||||||
* @return A number between 0 (start of text) and the text length.
|
* @return A number between 0 (start of text) and the text length.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public int getStart() {
|
public int getStart() {
|
||||||
return this.start;
|
return this.start;
|
||||||
}
|
}
|
||||||
@ -30,6 +31,7 @@ public class Interval implements Intervalable {
|
|||||||
*
|
*
|
||||||
* @return A number between getStart() + 1 and the text length.
|
* @return A number between getStart() + 1 and the text length.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public int getEnd() {
|
public int getEnd() {
|
||||||
return this.end;
|
return this.end;
|
||||||
}
|
}
|
||||||
@ -39,6 +41,7 @@ public class Interval implements Intervalable {
|
|||||||
*
|
*
|
||||||
* @return The end position less the start position, plus one.
|
* @return The end position less the start position, plus one.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public int size() {
|
public int size() {
|
||||||
return end - start + 1;
|
return end - start + 1;
|
||||||
}
|
}
|
||||||
@ -47,6 +50,7 @@ public class Interval implements Intervalable {
|
|||||||
* Answers whether the given interval overlaps this interval
|
* Answers whether the given interval overlaps this interval
|
||||||
* instance.
|
* instance.
|
||||||
*
|
*
|
||||||
|
* @param other
|
||||||
* @return true The intervals overlap.
|
* @return true The intervals overlap.
|
||||||
*/
|
*/
|
||||||
public boolean overlapsWith(final Interval other) {
|
public boolean overlapsWith(final Interval other) {
|
||||||
|
|||||||
@ -1,24 +1,20 @@
|
|||||||
package org.ahocorasick.trie;
|
package org.ahocorasick.trie;
|
||||||
|
|
||||||
import org.ahocorasick.interval.IntervalTree;
|
import static java.lang.Character.isWhitespace;
|
||||||
import org.ahocorasick.interval.Intervalable;
|
|
||||||
import org.ahocorasick.trie.handler.DefaultEmitHandler;
|
|
||||||
import org.ahocorasick.trie.handler.EmitHandler;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.LinkedBlockingDeque;
|
import java.util.concurrent.LinkedBlockingDeque;
|
||||||
|
import org.ahocorasick.interval.IntervalTree;
|
||||||
import static java.lang.Character.*;
|
import org.ahocorasick.interval.Intervalable;
|
||||||
|
import org.ahocorasick.trie.handler.DefaultEmitHandler;
|
||||||
import java.lang.Character;
|
import org.ahocorasick.trie.handler.EmitHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Based on the Aho-Corasick white paper, Bell technologies:
|
* Based on the Aho-Corasick white paper, Bell technologies:
|
||||||
* http://cr.yp.to/bib/1975/aho.pdf
|
* http://cr.yp.to/bib/1975/aho.pdf
|
||||||
*
|
*
|
||||||
* @author Robert Bor
|
* @author Robert Bor
|
||||||
*/
|
*/
|
||||||
public class Trie {
|
public class Trie {
|
||||||
@ -31,41 +27,66 @@ public class Trie {
|
|||||||
this.trieConfig = trieConfig;
|
this.trieConfig = trieConfig;
|
||||||
this.rootState = new State();
|
this.rootState = new State();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used by the builder to add a text search keyword.
|
* Used by the builder to add a text search keyword.
|
||||||
*
|
*
|
||||||
* @param keyword The search term to add to the list of search terms.
|
* @param keyword The search term to add to the list of search terms.
|
||||||
|
*
|
||||||
* @throws NullPointerException if the keyword is null.
|
* @throws NullPointerException if the keyword is null.
|
||||||
*/
|
*/
|
||||||
private void addKeyword(String keyword) {
|
private void addKeyword(String keyword) {
|
||||||
if (keyword.length() > 0) {
|
if( keyword.isEmpty() ) {
|
||||||
if (isCaseInsensitive()) {
|
return;
|
||||||
keyword = keyword.toLowerCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
addState(keyword).addEmit(keyword);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( isCaseInsensitive() ) {
|
||||||
|
keyword = keyword.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
addState(keyword).addEmit(keyword);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delegates to addKeyword.
|
||||||
|
*
|
||||||
|
* @param keywords List of search term to add to the list of search terms.
|
||||||
|
*/
|
||||||
|
private void addKeywords( final String[] keywords ) {
|
||||||
|
for( final String keyword : keywords ) {
|
||||||
|
addKeyword( keyword );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delegates to addKeyword.
|
||||||
|
*
|
||||||
|
* @param keywords List of search term to add to the list of search terms.
|
||||||
|
*/
|
||||||
|
private void addKeywords( final Collection<String> keywords ) {
|
||||||
|
for( final String keyword : keywords ) {
|
||||||
|
addKeyword( keyword );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private State addState(final String keyword) {
|
private State addState(final String keyword) {
|
||||||
return getRootState().addState(keyword);
|
return getRootState().addState(keyword);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<Token> tokenize(final String text) {
|
public Collection<Token> tokenize(final String text) {
|
||||||
final Collection<Token> tokens = new ArrayList<>();
|
final Collection<Token> tokens = new ArrayList<>();
|
||||||
final Collection<Emit> collectedEmits = parseText(text);
|
final Collection<Emit> collectedEmits = parseText(text);
|
||||||
int lastCollectedPosition = -1;
|
int lastCollectedPosition = -1;
|
||||||
|
|
||||||
for (final Emit emit : collectedEmits) {
|
for (final Emit emit : collectedEmits) {
|
||||||
if (emit.getStart() - lastCollectedPosition > 1) {
|
if (emit.getStart() - lastCollectedPosition > 1) {
|
||||||
tokens.add(createFragment(emit, text, lastCollectedPosition));
|
tokens.add(createFragment(emit, text, lastCollectedPosition));
|
||||||
}
|
}
|
||||||
|
|
||||||
tokens.add(createMatch(emit, text));
|
tokens.add(createMatch(emit, text));
|
||||||
lastCollectedPosition = emit.getEnd();
|
lastCollectedPosition = emit.getEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (text.length() - lastCollectedPosition > 1) {
|
if (text.length() - lastCollectedPosition > 1) {
|
||||||
tokens.add(createFragment(null, text, lastCollectedPosition));
|
tokens.add(createFragment(null, text, lastCollectedPosition));
|
||||||
}
|
}
|
||||||
@ -73,15 +94,12 @@ public class Trie {
|
|||||||
return tokens;
|
return tokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Token createFragment(
|
private Token createFragment(final Emit emit, final String text, final int lastCollectedPosition) {
|
||||||
final Emit emit,
|
return new FragmentToken(text.substring(lastCollectedPosition+1, emit == null ? text.length() : emit.getStart()));
|
||||||
final String text,
|
|
||||||
final int lastCollectedPosition) {
|
|
||||||
return new FragmentToken(text.substring(lastCollectedPosition + 1, emit == null ? text.length() : emit.getStart()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Token createMatch(final Emit emit, final String text) {
|
private Token createMatch(Emit emit, String text) {
|
||||||
return new MatchToken(text.substring(emit.getStart(), emit.getEnd() + 1), emit);
|
return new MatchToken(text.substring(emit.getStart(), emit.getEnd()+1), emit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@ -100,7 +118,7 @@ public class Trie {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!trieConfig.isAllowOverlaps()) {
|
if (!trieConfig.isAllowOverlaps()) {
|
||||||
IntervalTree intervalTree = new IntervalTree((List<Intervalable>) (List<?>) collectedEmits);
|
IntervalTree intervalTree = new IntervalTree((List<Intervalable>)(List<?>)collectedEmits);
|
||||||
intervalTree.removeOverlaps((List<Intervalable>) (List<?>) collectedEmits);
|
intervalTree.removeOverlaps((List<Intervalable>) (List<?>) collectedEmits);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,15 +131,15 @@ public class Trie {
|
|||||||
|
|
||||||
public void parseText(final CharSequence text, final EmitHandler emitHandler) {
|
public void parseText(final CharSequence text, final EmitHandler emitHandler) {
|
||||||
State currentState = getRootState();
|
State currentState = getRootState();
|
||||||
|
|
||||||
for (int position = 0; position < text.length(); position++) {
|
for (int position = 0; position < text.length(); position++) {
|
||||||
Character character = text.charAt(position);
|
Character character = text.charAt(position);
|
||||||
|
|
||||||
// TODO: Maybe lowercase the entire string at once?
|
// TODO: Maybe lowercase the entire string at once?
|
||||||
if (trieConfig.isCaseInsensitive()) {
|
if (trieConfig.isCaseInsensitive()) {
|
||||||
character = toLowerCase(character);
|
character = Character.toLowerCase(character);
|
||||||
}
|
}
|
||||||
|
|
||||||
currentState = getState(currentState, character);
|
currentState = getState(currentState, character);
|
||||||
if (storeEmits(position, currentState, emitHandler) && trieConfig.isStopOnHit()) {
|
if (storeEmits(position, currentState, emitHandler) && trieConfig.isStopOnHit()) {
|
||||||
return;
|
return;
|
||||||
@ -129,28 +147,35 @@ public class Trie {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The first matching text sequence.
|
||||||
|
*
|
||||||
|
* @param text The text to search for keywords.
|
||||||
|
* @return null if no matches found.
|
||||||
|
*/
|
||||||
public Emit firstMatch(final CharSequence text) {
|
public Emit firstMatch(final CharSequence text) {
|
||||||
if (!trieConfig.isAllowOverlaps()) {
|
if (!trieConfig.isAllowOverlaps()) {
|
||||||
// Slow path. Needs to find all the matches to detect overlaps.
|
// Slow path. Needs to find all the matches to detect overlaps.
|
||||||
Collection<Emit> parseText = parseText(text);
|
final Collection<Emit> parseText = parseText(text);
|
||||||
|
|
||||||
if (parseText != null && !parseText.isEmpty()) {
|
if (parseText != null && !parseText.isEmpty()) {
|
||||||
return parseText.iterator().next();
|
return parseText.iterator().next();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Fast path. Returns first match found.
|
// Fast path. Returns first match found.
|
||||||
State currentState = getRootState();
|
State currentState = getRootState();
|
||||||
|
|
||||||
for (int position = 0; position < text.length(); position++) {
|
for (int position = 0; position < text.length(); position++) {
|
||||||
Character character = text.charAt(position);
|
Character character = text.charAt(position);
|
||||||
|
|
||||||
// TODO: Lowercase the entire string at once?
|
// TODO: Lowercase the entire string at once?
|
||||||
if (trieConfig.isCaseInsensitive()) {
|
if (trieConfig.isCaseInsensitive()) {
|
||||||
character = toLowerCase(character);
|
character = Character.toLowerCase(character);
|
||||||
}
|
}
|
||||||
|
|
||||||
currentState = getState(currentState, character);
|
currentState = getState(currentState, character);
|
||||||
Collection<String> emitStrs = currentState.emit();
|
Collection<String> emitStrs = currentState.emit();
|
||||||
|
|
||||||
if (emitStrs != null && !emitStrs.isEmpty()) {
|
if (emitStrs != null && !emitStrs.isEmpty()) {
|
||||||
for (final String emitStr : emitStrs) {
|
for (final String emitStr : emitStrs) {
|
||||||
final Emit emit = new Emit(position - emitStr.length() + 1, position, emitStr);
|
final Emit emit = new Emit(position - emitStr.length() + 1, position, emitStr);
|
||||||
@ -165,26 +190,26 @@ public class Trie {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isPartialMatch(final CharSequence searchText, final Emit emit) {
|
private boolean isPartialMatch(final CharSequence searchText, final Emit emit) {
|
||||||
return (emit.getStart() != 0 &&
|
return (emit.getStart() != 0 &&
|
||||||
isAlphabetic(searchText.charAt(emit.getStart() - 1))) ||
|
Character.isAlphabetic(searchText.charAt(emit.getStart() - 1))) ||
|
||||||
(emit.getEnd() + 1 != searchText.length() &&
|
(emit.getEnd() + 1 != searchText.length() &&
|
||||||
isAlphabetic(searchText.charAt(emit.getEnd() + 1)));
|
Character.isAlphabetic(searchText.charAt(emit.getEnd() + 1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removePartialMatches(final CharSequence searchText, final List<Emit> collectedEmits) {
|
private void removePartialMatches(final CharSequence searchText, final List<Emit> collectedEmits) {
|
||||||
final List<Emit> removeEmits = new ArrayList<>();
|
final List<Emit> removeEmits = new ArrayList<>();
|
||||||
|
|
||||||
for (final Emit emit : collectedEmits) {
|
for (final Emit emit : collectedEmits) {
|
||||||
if (isPartialMatch(searchText, emit)) {
|
if (isPartialMatch(searchText, emit)) {
|
||||||
removeEmits.add(emit);
|
removeEmits.add(emit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (final Emit removeEmit : removeEmits) {
|
for (final Emit removeEmit : removeEmits) {
|
||||||
collectedEmits.remove(removeEmit);
|
collectedEmits.remove(removeEmit);
|
||||||
}
|
}
|
||||||
@ -193,30 +218,29 @@ public class Trie {
|
|||||||
private void removePartialMatchesWhiteSpaceSeparated(final CharSequence searchText, final List<Emit> collectedEmits) {
|
private void removePartialMatchesWhiteSpaceSeparated(final CharSequence searchText, final List<Emit> collectedEmits) {
|
||||||
final long size = searchText.length();
|
final long size = searchText.length();
|
||||||
final List<Emit> removeEmits = new ArrayList<>();
|
final List<Emit> removeEmits = new ArrayList<>();
|
||||||
|
|
||||||
for (final Emit emit : collectedEmits) {
|
for (final Emit emit : collectedEmits) {
|
||||||
if ((emit.getStart() == 0 || isWhitespace(searchText.charAt(emit.getStart() - 1))) &&
|
if ((emit.getStart() == 0 || isWhitespace(searchText.charAt(emit.getStart() - 1))) &&
|
||||||
(emit.getEnd() + 1 == size || isWhitespace(searchText.charAt(emit.getEnd() + 1)))) {
|
(emit.getEnd() + 1 == size || isWhitespace(searchText.charAt(emit.getEnd() + 1)))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
removeEmits.add(emit);
|
removeEmits.add(emit);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (final Emit removeEmit : removeEmits) {
|
for (final Emit removeEmit : removeEmits) {
|
||||||
collectedEmits.remove(removeEmit);
|
collectedEmits.remove(removeEmit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private State getState(final State initialState, final Character character) {
|
private State getState(State currentState, final Character character) {
|
||||||
State currentState = initialState;
|
State newCurrentState = currentState.nextState(character);
|
||||||
State updatedState = currentState.nextState(character);
|
|
||||||
|
while (newCurrentState == null) {
|
||||||
while (updatedState == null) {
|
|
||||||
currentState = currentState.failure();
|
currentState = currentState.failure();
|
||||||
updatedState = currentState.nextState(character);
|
newCurrentState = currentState.nextState(character);
|
||||||
}
|
}
|
||||||
|
|
||||||
return updatedState;
|
return newCurrentState;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void constructFailureStates() {
|
private void constructFailureStates() {
|
||||||
@ -249,13 +273,10 @@ public class Trie {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean storeEmits(
|
private boolean storeEmits(final int position, final State currentState, final EmitHandler emitHandler) {
|
||||||
final int position,
|
|
||||||
final State currentState,
|
|
||||||
final EmitHandler emitHandler) {
|
|
||||||
boolean emitted = false;
|
boolean emitted = false;
|
||||||
final Collection<String> emits = currentState.emit();
|
final Collection<String> emits = currentState.emit();
|
||||||
|
|
||||||
// TODO: The check for empty might be superfluous.
|
// TODO: The check for empty might be superfluous.
|
||||||
if (emits != null && !emits.isEmpty()) {
|
if (emits != null && !emits.isEmpty()) {
|
||||||
for (final String emit : emits) {
|
for (final String emit : emits) {
|
||||||
@ -263,31 +284,27 @@ public class Trie {
|
|||||||
emitted = true;
|
emitted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return emitted;
|
return emitted;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isCaseInsensitive() {
|
private boolean isCaseInsensitive() {
|
||||||
return trieConfig.isCaseInsensitive();
|
return trieConfig.isCaseInsensitive();
|
||||||
}
|
}
|
||||||
|
|
||||||
private State getRootState() {
|
private State getRootState() {
|
||||||
return this.rootState;
|
return this.rootState;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a TrieBuilder instance for configuring the Trie using a fluent
|
* Provides a fluent interface for constructing Trie instances.
|
||||||
* interface.
|
*
|
||||||
*
|
|
||||||
* @return The builder used to configure its Trie.
|
* @return The builder used to configure its Trie.
|
||||||
*/
|
*/
|
||||||
public static TrieBuilder builder() {
|
public static TrieBuilder builder() {
|
||||||
return new TrieBuilder();
|
return new TrieBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides a fluent interface for constructing Trie instances.
|
|
||||||
*/
|
|
||||||
public static class TrieBuilder {
|
public static class TrieBuilder {
|
||||||
|
|
||||||
private final TrieConfig trieConfig = new TrieConfig();
|
private final TrieConfig trieConfig = new TrieConfig();
|
||||||
@ -297,73 +314,75 @@ public class Trie {
|
|||||||
/**
|
/**
|
||||||
* Default (empty) constructor.
|
* Default (empty) constructor.
|
||||||
*/
|
*/
|
||||||
private TrieBuilder() {
|
private TrieBuilder() {}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a keyword to the Trie's list of text search keywords.
|
* Configure the Trie to ignore case when searching for keywords in
|
||||||
*
|
* the text. This must be called before calling addKeyword because
|
||||||
* @param keyword The keyword to add to the list.
|
* the algorithm converts keywords to lowercase as they are added,
|
||||||
* @return This builder.
|
* depending on this case sensitivity setting.
|
||||||
* @throws NullPointerException if the keyword is null.
|
*
|
||||||
*/
|
|
||||||
public TrieBuilder addKeyword(final CharSequence keyword) {
|
|
||||||
getTrie().addKeyword(keyword.toString());
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a list of keywords to the Trie's list of text search keywords.
|
|
||||||
*
|
|
||||||
* @param keywords The keywords to add to the list.
|
|
||||||
* @return This builder.
|
|
||||||
*/
|
|
||||||
public TrieBuilder addKeywords(final CharSequence... keywords) {
|
|
||||||
for (final CharSequence keyword : keywords) {
|
|
||||||
addKeyword(keyword);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a list of keywords to the Trie's list of text search keywords.
|
|
||||||
*
|
|
||||||
* @param keywords The keywords to add to the list.
|
|
||||||
* @return This builder.
|
|
||||||
*/
|
|
||||||
public TrieBuilder addKeywords(final Collection<CharSequence> keywords) {
|
|
||||||
return addKeywords(keywords.toArray(new CharSequence[keywords.size()]));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure the Trie to ignore case when searching for keywords in the
|
|
||||||
* text.
|
|
||||||
*
|
|
||||||
* @return This builder.
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public TrieBuilder ignoreCase() {
|
public TrieBuilder ignoreCase() {
|
||||||
getTrieConfig().setCaseInsensitive(true);
|
this.trieConfig.setCaseInsensitive(true);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure the Trie to ignore overlapping keywords.
|
* Configure the Trie to ignore overlapping keywords.
|
||||||
*
|
*
|
||||||
* @return This builder.
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public TrieBuilder ignoreOverlaps() {
|
public TrieBuilder ignoreOverlaps() {
|
||||||
getTrieConfig().setAllowOverlaps(false);
|
this.trieConfig.setAllowOverlaps(false);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a keyword to the Trie's list of text search keywords.
|
||||||
|
*
|
||||||
|
* @param keyword The keyword to add to the list.
|
||||||
|
*
|
||||||
|
* @return This builder.
|
||||||
|
* @throws NullPointerException if the keyword is null.
|
||||||
|
*/
|
||||||
|
public TrieBuilder addKeyword(final String keyword) {
|
||||||
|
this.trie.addKeyword(keyword);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a list of keywords to the Trie's list of text search keywords.
|
||||||
|
*
|
||||||
|
* @param keywords The keywords to add to the list.
|
||||||
|
*
|
||||||
|
* @return This builder.
|
||||||
|
*/
|
||||||
|
public TrieBuilder addKeywords(final String... keywords) {
|
||||||
|
this.trie.addKeywords(keywords);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a list of keywords to the Trie's list of text search keywords.
|
||||||
|
*
|
||||||
|
* @param keywords The keywords to add to the list.
|
||||||
|
*
|
||||||
|
* @return This builder.
|
||||||
|
*/
|
||||||
|
public TrieBuilder addKeywords(final Collection<String> keywords) {
|
||||||
|
this.trie.addKeywords(keywords);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure the Trie to match whole keywords in the text.
|
* Configure the Trie to match whole keywords in the text.
|
||||||
*
|
*
|
||||||
* @return This builder.
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public TrieBuilder onlyWholeWords() {
|
public TrieBuilder onlyWholeWords() {
|
||||||
getTrieConfig().setOnlyWholeWords(true);
|
this.trieConfig.setOnlyWholeWords(true);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,52 +390,39 @@ public class Trie {
|
|||||||
* Configure the Trie to match whole keywords that are separated by
|
* Configure the Trie to match whole keywords that are separated by
|
||||||
* whitespace in the text. For example, "this keyword thatkeyword"
|
* whitespace in the text. For example, "this keyword thatkeyword"
|
||||||
* would only match the first occurrence of "keyword".
|
* would only match the first occurrence of "keyword".
|
||||||
*
|
*
|
||||||
* @return This builder.
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public TrieBuilder onlyWholeWordsWhiteSpaceSeparated() {
|
public TrieBuilder onlyWholeWordsWhiteSpaceSeparated() {
|
||||||
getTrieConfig().setOnlyWholeWordsWhiteSpaceSeparated(true);
|
this.trieConfig.setOnlyWholeWordsWhiteSpaceSeparated(true);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure the Trie to stop searching for matches after the first
|
* Configure the Trie to stop after the first keyword is found in the
|
||||||
* keyword is found in the text.
|
* text.
|
||||||
*
|
*
|
||||||
* @return This builder.
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public TrieBuilder onlyFirstMatch() {
|
public TrieBuilder stopOnHit() {
|
||||||
getTrieConfig().setStopOnHit(true);
|
trie.trieConfig.setStopOnHit(true);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct the Trie using the builder settings.
|
* Configure the Trie based on the builder settings.
|
||||||
*
|
*
|
||||||
* @return The configured Trie.
|
* @return The configured Trie.
|
||||||
*/
|
*/
|
||||||
public Trie build() {
|
public Trie build() {
|
||||||
getTrie().constructFailureStates();
|
this.trie.constructFailureStates();
|
||||||
return getTrie();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Trie getTrie() {
|
|
||||||
return this.trie;
|
return this.trie;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TrieConfig getTrieConfig() {
|
|
||||||
return this.trieConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Use onlyFirstMatch()
|
|
||||||
*/
|
|
||||||
public TrieBuilder stopOnHit() {
|
|
||||||
return onlyFirstMatch();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use ignoreCase()
|
* @deprecated Use ignoreCase()
|
||||||
|
*
|
||||||
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public TrieBuilder caseInsensitive() {
|
public TrieBuilder caseInsensitive() {
|
||||||
return ignoreCase();
|
return ignoreCase();
|
||||||
@ -424,6 +430,8 @@ public class Trie {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use ignoreOverlaps()
|
* @deprecated Use ignoreOverlaps()
|
||||||
|
*
|
||||||
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public TrieBuilder removeOverlaps() {
|
public TrieBuilder removeOverlaps() {
|
||||||
return ignoreOverlaps();
|
return ignoreOverlaps();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user