Improves HiraganaMatcher.

This commit is contained in:
falsycat 2021-08-26 20:26:13 +09:00
parent 5d667f2894
commit 59d84172c5
2 changed files with 227 additions and 69 deletions

View File

@ -6,94 +6,248 @@
#include "common.h" #include "common.h"
static const std::vector<std::pair<std::wstring, std::wstring>> kPatterns = { static const size_t kPatternMax = 3;
{ L"ka", L"", },
{ L"ki", L"", }, static const std::map<std::wstring, std::vector<std::wstring>> kPatterns = {
{ L"ku", L"", }, { L"", { L"a" } },
{ L"ke", L"", }, { L"", { L"i" } },
{ L"ko", L"", }, { L"", { L"u" } },
{ L"sa", L"", }, { L"", { L"e" } },
{ L"si", L"", }, { L"", { L"o" } },
{ L"su", L"", }, { L"", { L"ka" } },
{ L"se", L"", }, { L"", { L"ki" } },
{ L"so", L"", }, { L"", { L"ku" } },
{ L"ta", L"", }, { L"", { L"ke" } },
{ L"ti", L"", }, { L"", { L"ko" } },
{ L"tu", L"", }, { L"", { L"ga" } },
{ L"te", L"", }, { L"", { L"gi" } },
{ L"to", L"", }, { L"", { L"gu" } },
{ L"na", L"", }, { L"", { L"ge" } },
{ L"ni", L"", }, { L"", { L"go" } },
{ L"nu", L"", }, { L"", { L"sa" } },
{ L"ne", L"", }, { L"", { L"si", L"shi" }},
{ L"no", L"", }, { L"", { L"su" } },
{ L"a", L"", }, { L"", { L"se" } },
{ L"i", L"", }, { L"", { L"so" } },
{ L"u", L"", }, { L"", { L"za" } },
{ L"e", L"", }, { L"", { L"zi", L"ji" }},
{ L"o", L"", }, { L"", { L"zu" } },
{ L"", { L"ze" } },
{ L"", { L"zo" } },
{ L"", { L"ta" } },
{ L"", { L"ti", L"chi" }},
{ L"", { L"tu", L"tsu"}},
{ L"", { L"te" } },
{ L"", { L"to" } },
{ L"", { L"da" } },
{ L"", { L"di" } },
{ L"", { L"du" } },
{ L"", { L"de" } },
{ L"", { L"do" } },
{ L"", { L"na" } },
{ L"", { L"ni" } },
{ L"", { L"nu" } },
{ L"", { L"ne" } },
{ L"", { L"no" } },
{ L"", { L"ha" } },
{ L"", { L"hi" } },
{ L"", { L"hu", L"fu" }},
{ L"", { L"he" } },
{ L"", { L"ho" } },
{ L"", { L"ba" } },
{ L"", { L"bi" } },
{ L"", { L"bu" } },
{ L"", { L"be" } },
{ L"", { L"bo" } },
{ L"", { L"pa" } },
{ L"", { L"pi" } },
{ L"", { L"pu" } },
{ L"", { L"pe" } },
{ L"", { L"po" } },
{ L"", { L"ma" } },
{ L"", { L"mi" } },
{ L"", { L"mu" } },
{ L"", { L"me" } },
{ L"", { L"mo" } },
{ L"", { L"ya" } },
{ L"", { L"yu" } },
{ L"", { L"yo" } },
{ L"きゃ", { L"kya" } },
{ L"きゅ", { L"kyu" } },
{ L"きょ", { L"kyo" } },
{ L"しゃ", { L"sha", L"sya" }},
{ L"しゅ", { L"shu", L"syu" }},
{ L"しょ", { L"sho", L"syo" }},
{ L"じゃ", { L"ja", L"zya" }},
{ L"じゅ", { L"ju", L"zyu" }},
{ L"じぇ", { L"je", L"zye" }},
{ L"じょ", { L"jo", L"zyo" }},
{ L"ちゃ", { L"cha", L"tya" }},
{ L"ちゅ", { L"chu", L"tyu" }},
{ L"ちょ", { L"cho", L"tyo" }},
{ L"", { L"ra" } },
{ L"", { L"ri" } },
{ L"", { L"ru" } },
{ L"", { L"re" } },
{ L"", { L"ro" } },
{ L"", { L"wa" } },
{ L"", { L"wo" } },
{ L"", { L"n", L"nn"}},
{ L"", { L"ltu", L"xtu" }},
{ L"っか", { L"kka" } },
{ L"っき", { L"kki" } },
{ L"っく", { L"kku" } },
{ L"っけ", { L"kke" } },
{ L"っこ", { L"kko" } },
{ L"っが", { L"gga" } },
{ L"っぎ", { L"ggi" } },
{ L"っぐ", { L"ggu" } },
{ L"っげ", { L"gge" } },
{ L"っご", { L"ggo" } },
{ L"っさ", { L"ssa" } },
{ L"っし", { L"ssi" } },
{ L"っす", { L"ssu" } },
{ L"っせ", { L"sse" } },
{ L"っそ", { L"sso" } },
{ L"っざ", { L"zza" } },
{ L"っじ", { L"zzi", L"jji" }},
{ L"っず", { L"zzu" } },
{ L"っぜ", { L"zze" } },
{ L"っぞ", { L"zzo" } },
{ L"った", { L"tta" } },
{ L"っち", { L"tti", L"cchi" }},
{ L"っつ", { L"ttu", L"ttsu"}},
{ L"って", { L"tte" } },
{ L"っと", { L"tto" } },
{ L"っだ", { L"dda" } },
{ L"っぢ", { L"ddi" } },
{ L"っづ", { L"ddu" } },
{ L"っで", { L"dde" } },
{ L"っど", { L"ddo" } },
{ L"っな", { L"nna" } },
{ L"っに", { L"nni" } },
{ L"っぬ", { L"nnu" } },
{ L"っね", { L"nne" } },
{ L"っの", { L"nno" } },
{ L"っは", { L"hha" } },
{ L"っひ", { L"hhi" } },
{ L"っふ", { L"hhu", L"ffu" }},
{ L"っへ", { L"hhe" } },
{ L"っほ", { L"hho" } },
{ L"っば", { L"bba" } },
{ L"っび", { L"bbi" } },
{ L"っぶ", { L"bbu" } },
{ L"っべ", { L"bbe" } },
{ L"っぼ", { L"bbo" } },
{ L"っぱ", { L"ppa" } },
{ L"っぴ", { L"ppi" } },
{ L"っぷ", { L"ppu" } },
{ L"っぺ", { L"ppe" } },
{ L"っぽ", { L"ppo" } },
{ L"っま", { L"mma" } },
{ L"っみ", { L"mmi" } },
{ L"っむ", { L"mmu" } },
{ L"っめ", { L"mme" } },
{ L"っも", { L"mmo" } },
{ L"っや", { L"yya" } },
{ L"っゆ", { L"yyu" } },
{ L"っよ", { L"yyo" } },
{ L"っら", { L"rra" } },
{ L"っり", { L"rri" } },
{ L"っる", { L"rru" } },
{ L"っれ", { L"rre" } },
{ L"っろ", { L"rro" } },
{ L"", { L"wwa" } },
{ L"", { L"wwo" } },
}; };
bool gj::HiraganaMatcher::Input(wchar_t c) { bool gj::HiraganaMatcher::Input_(wchar_t c, bool force_cut) {
assert(!done()); assert(!done());
const std::wstring newbuf = force_cut? buffer_: buffer_ + c;
const std::wstring remain = state_.text.substr(state_.match); const std::wstring remain = state_.text.substr(state_.match);
const std::wstring newbuf = buffer_ + c;
const size_t n = newbuf.size(); const size_t pattern_len = std::min(kPatternMax, remain.size());
size_t last_match = 0;
bool accept = false; bool accept = false;
for (size_t i = 0; i < kPatterns.size(); ++i) { size_t part_match = 0;
const auto& pattern = kPatterns[i]; size_t comp_match = 0;
if (pattern.first.substr(0, n) == newbuf) { for (size_t i = 1; i <= pattern_len; ++i) {
const size_t pn = pattern.second.size(); const auto& p = kPatterns.find(remain.substr(0, i));
if (remain.substr(0, pn) == pattern.second) { if (p == kPatterns.end()) continue;
accept = true;
last_match = i; const auto& preds = p->second;
for (const auto& itr : preds) {
if (newbuf.size() == 0 || itr.size() < newbuf.size()) {
continue;
} }
if (pattern.first.size() == n) {
if (!accept) return false; if (itr.substr(0, newbuf.size()) == newbuf) {
state_.match += pn; accept = true;
buffer_ = L""; if (itr.size() == newbuf.size()) {
UpdateExpects(i); comp_match = i;
if (force_cut) {
buffer_ = {c};
state_.match += i;
UpdateExpects_();
return true; return true;
} }
} else {
part_match = i;
}
}
} }
} }
if (accept) { if (force_cut) {
buffer_ = newbuf; return false;
UpdateExpects(last_match);
} }
return accept; if (!accept) {
return Input_(c, true);
} }
void gj::HiraganaMatcher::UpdateExpects(size_t last_match) { if (comp_match > part_match) {
std::wstring text = state_.text.substr(state_.match); buffer_ = L"";
state_.match += comp_match;
UpdateExpects_();
return true;
}
buffer_ += c;
UpdateExpects_();
return true;
}
void gj::HiraganaMatcher::UpdateExpects_() {
std::wstring remain = state_.text.substr(state_.match);
expects_ = L""; expects_ = L"";
if (text.empty()) return;
if (last_match < SIZE_MAX && buffer_.size()) { bool first = true;
expects_ = kPatterns[last_match].first.substr(buffer_.size()); while (remain.size()) {
text = text.substr(kPatterns[last_match].second.size()); const size_t prev = remain.size();
} for (size_t len = std::min(kPatternMax, remain.size()); len > 0; --len) {
const auto& p = kPatterns.find(remain.substr(0, len));
if (p == kPatterns.end()) continue;
while (text.size()) { const auto& preds = p->second;
bool match = false; if (first) {
for (const auto& pattern : kPatterns) { for (const auto& itr : preds) {
const size_t n = pattern.second.size(); if (itr.size() < buffer_.size()) continue;
if (text.size() < n) continue; if (itr.substr(0, buffer_.size()) == buffer_) {
expects_ += itr.substr(buffer_.size());
if (text.substr(0, n) == pattern.second) { first = false;
expects_ += pattern.first;
text = text.substr(n);
match = true;
break; break;
} }
} }
if (!match) Abort("hiragana janai"); if (first) continue;
} else {
expects_ += preds[0];
}
remain = remain.substr(len);
}
if (prev == remain.size()) Abort("invalid pattern for InputWin");
} }
} }

View File

@ -16,10 +16,12 @@ class HiraganaMatcher : public iInputMatcher {
HiraganaMatcher& operator=(const HiraganaMatcher&) = default; HiraganaMatcher& operator=(const HiraganaMatcher&) = default;
HiraganaMatcher(const std::wstring& text) : state_{text, 0} { HiraganaMatcher(const std::wstring& text) : state_{text, 0} {
UpdateExpects(); UpdateExpects_();
} }
bool Input(wchar_t c) override; bool Input(wchar_t c) override {
return Input_(c, false);
}
const std::wstring& expects() const override { const std::wstring& expects() const override {
return expects_; return expects_;
@ -33,11 +35,13 @@ class HiraganaMatcher : public iInputMatcher {
private: private:
std::wstring buffer_; std::wstring buffer_;
std::wstring expects_; std::wstring expects_;
State state_; State state_;
void UpdateExpects(size_t last_match = SIZE_MAX); bool Input_(wchar_t c, bool force_cut);
void UpdateExpects_();
}; };