From 95cb5fe91967e28a25cfc7d5b91b343cc9c42fe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B1=85=E6=88=8E=E6=B0=8F?= Date: Thu, 29 Feb 2024 01:05:46 +0800 Subject: [PATCH] feat(dictionary): predict word --- src/rime/dict/dictionary.cc | 19 ++++++++++++------- src/rime/dict/dictionary.h | 1 + src/rime/gear/script_translator.cc | 11 ++++++++--- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/rime/dict/dictionary.cc b/src/rime/dict/dictionary.cc index 9492d8d83..4a0085f1e 100644 --- a/src/rime/dict/dictionary.cc +++ b/src/rime/dict/dictionary.cc @@ -60,11 +60,14 @@ bool compare_chunk_by_head_element(const Chunk& a, const Chunk& b) { size_t match_extra_code(const table::Code* extra_code, size_t depth, const SyllableGraph& syll_graph, - size_t current_pos) { + size_t current_pos, + bool predict_word) { if (!extra_code || depth >= extra_code->size) return current_pos; // success - if (current_pos >= syll_graph.interpreted_length) - return 0; // failure (possibly success for completion in the future) + if (current_pos >= syll_graph.interpreted_length) { + return predict_word ? syll_graph.interpreted_length // word completion + : 0; // failure + } auto index = syll_graph.indices.find(current_pos); if (index == syll_graph.indices.end()) return 0; @@ -74,8 +77,8 @@ size_t match_extra_code(const table::Code* extra_code, return 0; size_t best_match = 0; for (const SpellingProperties* props : spellings->second) { - size_t match_end_pos = - match_extra_code(extra_code, depth + 1, syll_graph, props->end_pos); + size_t match_end_pos = match_extra_code(extra_code, depth + 1, syll_graph, + props->end_pos, predict_word); if (!match_end_pos) continue; if (match_end_pos > best_match) @@ -199,6 +202,7 @@ static void lookup_table(Table* table, DictEntryCollector* collector, const SyllableGraph& syllable_graph, size_t start_pos, + bool predict_word, double initial_credibility) { TableQueryResult result; if (!table->Query(syllable_graph, start_pos, &result)) { @@ -212,7 +216,7 @@ static void lookup_table(Table* table, if (a.extra_code()) { do { size_t actual_end_pos = dictionary::match_extra_code( - a.extra_code(), 0, syllable_graph, end_pos); + a.extra_code(), 0, syllable_graph, end_pos, predict_word); if (actual_end_pos == 0) continue; (*collector)[actual_end_pos].AddChunk( @@ -227,6 +231,7 @@ static void lookup_table(Table* table, an Dictionary::Lookup(const SyllableGraph& syllable_graph, size_t start_pos, + bool predict_word, double initial_credibility) { if (!loaded()) return nullptr; @@ -235,7 +240,7 @@ an Dictionary::Lookup(const SyllableGraph& syllable_graph, if (!table->IsOpen()) continue; lookup_table(table.get(), collector.get(), syllable_graph, start_pos, - initial_credibility); + predict_word, initial_credibility); } if (collector->empty()) return nullptr; diff --git a/src/rime/dict/dictionary.h b/src/rime/dict/dictionary.h index cf0de9e47..76cce2b0a 100644 --- a/src/rime/dict/dictionary.h +++ b/src/rime/dict/dictionary.h @@ -73,6 +73,7 @@ class Dictionary : public Class { RIME_API an Lookup(const SyllableGraph& syllable_graph, size_t start_pos, + bool predict_word = false, double initial_credibility = 0.0); // if predictive is true, do an expand search with limit, // otherwise do an exact match. diff --git a/src/rime/gear/script_translator.cc b/src/rime/gear/script_translator.cc index 9506c9e7c..d0abf5edd 100644 --- a/src/rime/gear/script_translator.cc +++ b/src/rime/gear/script_translator.cc @@ -112,10 +112,12 @@ class ScriptTranslation : public Translation { Corrector* corrector, Poet* poet, const string& input, - size_t start) + size_t start, + size_t end_of_input) : translator_(translator), poet_(poet), start_(start), + end_of_input_(end_of_input), syllabifier_( New(translator, corrector, input, start)), enable_correction_(corrector) { @@ -137,6 +139,7 @@ class ScriptTranslation : public Translation { ScriptTranslator* translator_; Poet* poet_; size_t start_; + size_t end_of_input_; an syllabifier_; an phrase_; @@ -189,9 +192,10 @@ an ScriptTranslator::Query(const string& input, bool enable_user_dict = user_dict_ && user_dict_->loaded() && !IsUserDictDisabledFor(input); + size_t end_of_input = engine_->context()->input().length(); // the translator should survive translations it creates auto result = New(this, corrector_.get(), poet_.get(), - input, segment.start); + input, segment.start, end_of_input); if (!result || !result->Evaluate( dict_.get(), enable_user_dict ? user_dict_.get() : NULL)) { return nullptr; @@ -343,8 +347,9 @@ string ScriptSyllabifier::GetOriginalSpelling(const Phrase& cand) const { bool ScriptTranslation::Evaluate(Dictionary* dict, UserDictionary* user_dict) { size_t consumed = syllabifier_->BuildSyllableGraph(*dict->prism()); const auto& syllable_graph = syllabifier_->syllable_graph(); + bool predict_word = start_ + consumed == end_of_input_; - phrase_ = dict->Lookup(syllable_graph, 0); + phrase_ = dict->Lookup(syllable_graph, 0, predict_word); if (user_dict) { user_phrase_ = user_dict->Lookup(syllable_graph, 0); }