Os transdutores Levenshtein aceitam um termo de consulta e retornam todos os termos em um dicionário que estejam a n erros ortográficos dele. Eles constituem uma classe de corretores ortográficos altamente eficientes (espaço e tempo) que funcionam muito bem quando você não precisa de contexto ao fazer sugestões. Esqueça a realização de uma varredura linear em seu dicionário para encontrar todos os termos que estejam suficientemente próximos da consulta do usuário, usando uma implementação quadrática da distância Levenshtein ou distância Damerau-Levenshtein, esses bebês encontram todos os termos do seu dicionário em tempo linear em o comprimento do termo de consulta (não no tamanho do dicionário, mas no comprimento do termo de consulta).
Se você precisar de contexto, tome os candidatos gerados pelo transdutor como ponto de partida e conecte-os a qualquer modelo que estiver usando para contexto (por exemplo, selecionando a sequência de termos que tem a maior probabilidade de aparecerem juntos).
Para uma demonstração rápida, visite a página do Github, aqui. Há também uma interface de linha de comando, libvenshtein-java-cli. Consulte seu README.md para obter informações de aquisição e uso.
A biblioteca está atualmente escrita em Java, CoffeeScript e JavaScript, mas irei portá-la para outras linguagens em breve. Se você tiver um idioma específico no qual gostaria de vê-lo ou um sistema de gerenciamento de pacotes no qual gostaria de implementá-lo, me avise.
Filial | Descrição |
---|---|
mestre | Fonte de desenvolvimento mais recente |
liberar | Fonte de lançamento mais recente |
versão-3.x | Fonte de lançamento mais recente para a versão 3.x |
versão-2.x | Fonte de lançamento mais recente para a versão 2.x |
Os problemas são gerenciados em waffle.io. Abaixo você encontrará um gráfico da taxa com que os venho fechando.
Visite Bountysource para prometer seu apoio aos problemas em andamento.
Quando se trata de documentação, você tem várias opções:
Wikipédia
Javadoc
Código Fonte
libvenshtein foi desenvolvido em Java ≥ 1.8. Não funcionará com versões anteriores.
Adicione uma dependência do Maven ao Artifactory. Por exemplo, em um projeto Gradle, você modificaria seus repositories
da seguinte forma:
repositórios { especialista { url 'https://oss.jfrog.org/artifactory/oss-release-local' } }
Adicione uma dependência do Maven em um dos seguintes:
Maven Central
JCenter
Bandeja binária
<dependência> <groupId>com.github.universal-automata</groupId> <artifactId>liblevenshtein</artifactId> <versão>3.0.0</versão> </dependency>
'com.github.universal-automata:liblevenshtein:jar:3.0.0'
<dependency org="com.github.universal-automata" name="liblevenshtein" rev="3.0.0" />
@Uvas( @Grab(group='com.github.universal-automata', module='liblevenshtein', version='3.0.0') )
compilar 'com.github.universal-automata:liblevenshtein:3.0.0'
bibliotecaDependencies += "com.github.universal-automata" % "liblevenshtein" % "3.0.0"
[com.github.universal-automata/liblevenshtein "3.0.0"]
% git clone --progress [email protected]:universal-automata/liblevenshtein-java.git Cloning into 'liblevenshtein-java'... remote: Counting objects: 8117, done. remote: Compressing objects: 100% (472/472), done. remote: Total 8117 (delta 352), reused 0 (delta 0), pack-reused 7619 Receiving objects: 100% (8117/8117), 5.52 MiB | 289.00 KiB/s, done. Resolving deltas: 100% (5366/5366), done. Checking connectivity... done. % cd liblevenshtein-java % git pull --progress Already up-to-date. % git fetch --progress --tags % git checkout --progress 3.0.0 Note: checking out '3.0.0'. You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by performing another checkout. If you want to create a new branch to retain commits you create, you may do so (now or later) by using -b with the checkout command again. Example: git checkout -b <new-branch-name> HEAD is now at 4f0f172... pushd and popd silently % git submodule init % git submodule update
Digamos que você tenha o seguinte conteúdo em um arquivo de texto simples chamado top-20-most-most-common-english-words.txt (observe que o arquivo tem um termo por linha):
the be to of and a in that have I it for not on with he as you do at
O seguinte fornece uma maneira de consultar seu conteúdo:
importar java.io.InputStream;importar java.io.OutputStream;importar java.nio.file.Files;importar java.nio.file.Path;importar java.nio.file.Paths;importar com.github.liblevenshtein.collection. dicionário.SortedDawg;importar com.github.liblevenshtein.serialization.PlainTextSerializer;importar com.github.liblevenshtein.serialization.ProtobufSerializer;importar com.github.liblevenshtein.serialization.Serializer;importar com.github.liblevenshtein.transducer.Algorithm;importar com.github.liblevenshtein.transducer.Candidate;importar com.github.liblevenshtein. transdutor.ITransducer;importar com.github.liblevenshtein.transducer.factory.TransducerBuilder;// ...dicionário SortedDawg final;caminho final dicionárioPath = Paths.get("/path/to/top-20-most-common-english-words.txt") ;try (final InputStream stream = Files.newInputStream(dictionaryPath)) { // O construtor PlainTextSerializer aceita um booleano opcional especificando // se o dicionário já está ordenado lexicograficamente, em ordem crescente // ordem. Se estiver classificado, passar true otimizará a construção // do dicionário; você pode passar falso se o dicionário estiver classificado ou // não (este é o comportamento padrão e mais seguro se você não sabe se o // o dicionário é classificado). final Serializer serializer = new PlainTextSerializer(false); dicionário = serializer.deserialize(SortedDawg.class, stream); }final ITransducer<Candidato> transdutor = novo TransducerBuilder() .dictionary(dicionário) .algoritmo(Algoritmo.TRANSPOSIÇÃO) .defaultMaxDistance(2) .includeDistance(verdadeiro) .build();for (String final queryTerm: new String[] {"foo", "bar"}) { System.out.println("+---------------- -------------------------------------------------- -------------"); System.out.printf("| Ortografia de candidatos para termo de consulta: "%s"%n", queryTerm); System.out.println("+------------------------------------------ -------------------------------------"); para (candidato final: transducer.transduce(queryTerm)) {System.out.printf("| d("%s", "%s") = [%d]%n", queryTerm, candidate.term() , candidato.distance()); } }// +------------------------------------------------------------ ---------------------------------// | Ortografia dos candidatos ao termo de consulta: "foo"// +-------------------------------------- -----------------------------------------// | d("foo", "do") = [2]// | d("foo", "de") = [2]// | d("foo", "ligado") = [2]// | d("foo", "para") = [2]// | d("foo", "para") = [1]// | d("foo", "não") = [2]// | d("foo", "você") = [2]// +--------------------------------- --------------------------------------------------------// | Ortografia dos candidatos ao termo de consulta: "bar"// +-------------------------------------- -----------------------------------------// | d("barra", "a") = [2]// | d("barra", "como") = [2]// | d("barra", "em") = [2]// | d("barra", "ser") = [2]// | d("barra", "para") = [2]// ...
Se você quiser serializar seu dicionário em um formato que seja fácil de ler posteriormente, faça o seguinte:
caminho final serializedDictionaryPath = Paths.get("/path/to/top-20-most-common-english-words.protobuf.bytes");try (final OutputStream stream = Files.newOutputStream(serializedDictionaryPath)) { final Serializer serializer = novo ProtobufSerializer(); serializer.serialize (dicionário, fluxo); }
Então, você pode ler o dicionário mais tarde, da mesma forma que lê a versão em texto simples:
final SortedDawg deserializedDictionary;try (fluxo final de InputStream = Files.newInputStream(serializedDictionaryPath)) { final Serializer serializer = new ProtobufSerializer(); deserializedDictionary = serializer.deserialize(SortedDawg.class, stream); }
A serialização não está restrita a dicionários, você também pode (des)serializar transdutores.
Por favor, consulte o wiki para mais detalhes.
Esta biblioteca é baseada principalmente no trabalho de Stoyan Mihov, Klaus Schulz e Petar Nikolaev Mitankin: Fast String Correction with Levenshtein-Automata. Para obter mais informações, consulte o wiki.
liblevenshtein-java é mantido por@dylon ([email protected])