package com.scrivenvar.spelling.impl;
import com.scrivenvar.spelling.api.SpellCheckListener;
import com.scrivenvar.spelling.api.SpellChecker;
import io.gitlab.rxp90.jsymspell.SuggestItem;
import io.gitlab.rxp90.jsymspell.SymSpell;
import io.gitlab.rxp90.jsymspell.SymSpellBuilder;
import java.text.BreakIterator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import static io.gitlab.rxp90.jsymspell.SymSpell.Verbosity;
import static io.gitlab.rxp90.jsymspell.SymSpell.Verbosity.ALL;
import static io.gitlab.rxp90.jsymspell.SymSpell.Verbosity.CLOSEST;
import static java.lang.Character.isLetter;
public class SymSpellSpeller implements SpellChecker {
private final BreakIterator mBreakIterator = BreakIterator.getWordInstance();
private final SymSpell mSymSpell;
public static SpellChecker forLexicon(
final Collection<String> lexiconWords ) {
assert lexiconWords != null && !lexiconWords.isEmpty();
final SymSpellBuilder builder = new SymSpellBuilder()
.setLexiconWords( lexiconWords );
return new SymSpellSpeller( builder.build() );
}
private SymSpellSpeller( final SymSpell symSpell ) {
mSymSpell = symSpell;
}
@Override
public boolean inLexicon( final String lexeme ) {
return lookup( lexeme, CLOSEST ).size() == 1;
}
@Override
public List<String> suggestions( final String lexeme, int count ) {
final List<String> result = new ArrayList<>( count );
for( final var item : lookup( lexeme, ALL ) ) {
if( count-- > 0 ) {
result.add( item.getSuggestion() );
}
else {
break;
}
}
return result;
}
@Override
public void proofread(
final String text, final SpellCheckListener consumer ) {
assert text != null;
assert consumer != null;
mBreakIterator.setText( text );
int boundaryIndex = mBreakIterator.first();
int previousIndex = 0;
while( boundaryIndex != BreakIterator.DONE ) {
final String substring =
text.substring( previousIndex, boundaryIndex ).toLowerCase();
if( isWord( substring ) && !inLexicon( substring ) ) {
consumer.accept( substring, previousIndex, boundaryIndex );
}
previousIndex = boundaryIndex;
boundaryIndex = mBreakIterator.next();
}
}
private boolean isWord( final String word ) {
return !word.isEmpty() && isLetter( word.charAt( 0 ) );
}
private List<SuggestItem> lookup( final String lexeme, final Verbosity v ) {
return getSpeller().lookup( lexeme, v );
}
private SymSpell getSpeller() {
return mSymSpell;
}
}