put text positions on the transitions and track in the token stream
This commit is contained in:
parent
dd5f9b25fa
commit
b7bb0cbf5b
@ -21,13 +21,12 @@ package org.ahocorasick.trie;
|
|||||||
*/
|
*/
|
||||||
class CharacterTransition extends Transition<Character> {
|
class CharacterTransition extends Transition<Character> {
|
||||||
|
|
||||||
public CharacterTransition(Character c) {
|
public CharacterTransition(Character c, int start) {
|
||||||
super(c);
|
super(c, start, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public CharacterTransition(Character c) {
|
||||||
public void updateMatch(StringBuilder match) {
|
this(c, 0);
|
||||||
match.append(token);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -25,16 +25,27 @@ import java.util.Objects;
|
|||||||
*/
|
*/
|
||||||
public abstract class Transition<T> {
|
public abstract class Transition<T> {
|
||||||
protected final T token;
|
protected final T token;
|
||||||
|
protected final int start;
|
||||||
|
protected final int length;
|
||||||
|
|
||||||
public Transition(T token) {
|
public Transition(T token, int start, int length) {
|
||||||
this.token = token;
|
this.token = token;
|
||||||
|
this.start = start;
|
||||||
|
this.length = length;
|
||||||
}
|
}
|
||||||
|
|
||||||
public T transitionToken() {
|
public T transitionToken() {
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void updateMatch(StringBuilder match);
|
public int getStart() {
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLength() {
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
public abstract boolean isWordSeparator();
|
public abstract boolean isWordSeparator();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -31,11 +31,15 @@ public class Trie {
|
|||||||
this.rootState = new State();
|
this.rootState = new State();
|
||||||
}
|
}
|
||||||
|
|
||||||
private interface KeywordTokenizer {
|
private abstract class KeywordTokenizer {
|
||||||
public Transition nextTransition();
|
protected int position = 0;
|
||||||
|
public abstract Transition nextTransition();
|
||||||
|
public int getPosition() {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class WordTokenizer implements KeywordTokenizer {
|
private class WordTokenizer extends KeywordTokenizer {
|
||||||
private final Iterator<String> st;
|
private final Iterator<String> st;
|
||||||
public WordTokenizer(String keyword) {
|
public WordTokenizer(String keyword) {
|
||||||
String[] tokens = keyword.split("\\s");
|
String[] tokens = keyword.split("\\s");
|
||||||
@ -45,13 +49,18 @@ public class Trie {
|
|||||||
public Transition<String> nextTransition() {
|
public Transition<String> nextTransition() {
|
||||||
WordTransition t = null;
|
WordTransition t = null;
|
||||||
if (st.hasNext()) {
|
if (st.hasNext()) {
|
||||||
t = new WordTransition(st.next());
|
String word = st.next();
|
||||||
|
t = new WordTransition(word, position);
|
||||||
|
if (0 < position) {
|
||||||
|
position += 1; // a space
|
||||||
|
}
|
||||||
|
position += word.length();
|
||||||
}
|
}
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class CharacterTokenizer implements KeywordTokenizer {
|
private class CharacterTokenizer extends KeywordTokenizer {
|
||||||
private final java.text.StringCharacterIterator ct;
|
private final java.text.StringCharacterIterator ct;
|
||||||
private char cur;
|
private char cur;
|
||||||
public CharacterTokenizer(String keyword) {
|
public CharacterTokenizer(String keyword) {
|
||||||
@ -62,9 +71,10 @@ public class Trie {
|
|||||||
public Transition<Character> nextTransition() {
|
public Transition<Character> nextTransition() {
|
||||||
CharacterTransition t = null;
|
CharacterTransition t = null;
|
||||||
if (cur != CharacterIterator.DONE) {
|
if (cur != CharacterIterator.DONE) {
|
||||||
t = new CharacterTransition(cur);
|
t = new CharacterTransition(cur, position);
|
||||||
cur = ct.next();
|
cur = ct.next();
|
||||||
}
|
}
|
||||||
|
position += 1;
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,11 +92,18 @@ public class Trie {
|
|||||||
|
|
||||||
private class TokenStream {
|
private class TokenStream {
|
||||||
private final KeywordTokenizer kwt;
|
private final KeywordTokenizer kwt;
|
||||||
|
private final String input;
|
||||||
private Transition lookahead;
|
private Transition lookahead;
|
||||||
private final StringBuilder match = new StringBuilder();
|
|
||||||
|
|
||||||
public TokenStream(KeywordTokenizer kwt) {
|
public TokenStream(String input) {
|
||||||
this.kwt = kwt;
|
this.input = input;
|
||||||
|
if (trieConfig.hasWordTransitions()) {
|
||||||
|
kwt = new WordTokenizer(input);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
kwt = new CharacterTokenizer(input);
|
||||||
|
}
|
||||||
|
lookahead = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Transition nextTransition() {
|
public Transition nextTransition() {
|
||||||
@ -97,22 +114,15 @@ public class Trie {
|
|||||||
else {
|
else {
|
||||||
lookahead = null;
|
lookahead = null;
|
||||||
}
|
}
|
||||||
if (next != null) {
|
|
||||||
next.updateMatch(match);
|
|
||||||
}
|
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int position() {
|
|
||||||
return match.length() - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isWholeWord(int start) {
|
public boolean isWholeWord(int start) {
|
||||||
if (lookahead == null) {
|
if (lookahead == null) {
|
||||||
lookahead = kwt.nextTransition();
|
lookahead = kwt.nextTransition();
|
||||||
}
|
}
|
||||||
return ((start == 0 ||
|
return ((start == 0 ||
|
||||||
Character.isSpaceChar(match.codePointAt(start-1))) &&
|
Character.isSpaceChar(input.codePointAt(start-1))) &&
|
||||||
(lookahead == null || lookahead.isWordSeparator()));
|
(lookahead == null || lookahead.isWordSeparator()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -169,7 +179,7 @@ public class Trie {
|
|||||||
if (trieConfig.isCaseInsensitive()) {
|
if (trieConfig.isCaseInsensitive()) {
|
||||||
input = input.toLowerCase();
|
input = input.toLowerCase();
|
||||||
}
|
}
|
||||||
TokenStream tknz = new TokenStream(keywordTokenizer(input));
|
TokenStream tknz = new TokenStream(input);
|
||||||
|
|
||||||
State currentState = this.rootState;
|
State currentState = this.rootState;
|
||||||
Transition tn = tknz.nextTransition();
|
Transition tn = tknz.nextTransition();
|
||||||
@ -180,7 +190,7 @@ public class Trie {
|
|||||||
currentState = getState(currentState, tn, flushHandler);
|
currentState = getState(currentState, tn, flushHandler);
|
||||||
Collection<String> emits = currentState.emit();
|
Collection<String> emits = currentState.emit();
|
||||||
for (String emit : emits) {
|
for (String emit : emits) {
|
||||||
int position = tknz.position();
|
int position = tn.getStart() + tn.getLength() - 1;
|
||||||
int start = position - emit.length() + 1;
|
int start = position - emit.length() + 1;
|
||||||
boolean isWholeWord = tknz.isWholeWord(start);
|
boolean isWholeWord = tknz.isWholeWord(start);
|
||||||
if (isWholeWord || !trieConfig.isOnlyWholeWords()) {
|
if (isWholeWord || !trieConfig.isOnlyWholeWords()) {
|
||||||
|
|||||||
@ -21,21 +21,16 @@ package org.ahocorasick.trie;
|
|||||||
*/
|
*/
|
||||||
public class WordTransition extends Transition<String> {
|
public class WordTransition extends Transition<String> {
|
||||||
|
|
||||||
public WordTransition(String s) {
|
public WordTransition(String s, int start) {
|
||||||
super(s);
|
super(s, start, s.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public WordTransition(String s) {
|
||||||
public void updateMatch(StringBuilder match) {
|
this(s, 0);
|
||||||
if (0 < match.length()) {
|
|
||||||
match.append(' ');
|
|
||||||
}
|
|
||||||
match.append(token);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isWordSeparator() {
|
public boolean isWordSeparator() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user