Files
msime-windows/engine/direct_helpcode/spelling_graph.h
T
Lu Fan(SonnyCalcr) 22fb1e2569 Merge pull request #619 from fanlusky/feat/shuangpin-direct-helpcode
feat: 双拼直接辅助码(万象式,无需引导键)
2026-10-04 19:32:10 +08:00

94 lines
3.5 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#pragma once
#include "../shuangpin/shuangpin_profile.h"
#include <cstddef>
#include <functional>
#include <string>
#include <vector>
// 双拼直接辅助码(万象「直接辅助」)的拼写图。
//
// 万象把每个字的辅码写进词库音节(shí;dk),再用拼写运算派生出可敲的形式,librime 在按键位置上
// 把所有能匹配的拼写连成图、交给词格整句解码。这里在不改词库的前提下做同一件事:每个位置上
// 一个音节可以写成
//
// ui 双拼两键 Plain
// uia 双拼 + 第一位辅码 Aux1
// uiab/ 双拼 + 两位辅码 + / Aux2Slash
// uiab 双拼 + 两位辅码(不带 /) Aux2Abbrev 缩写,见下
// u 单个声母键 Initial 缩写,见下
//
// 辅码那一段只有在「这个音节下真有字的辅码以它开头」时才成立(AuxPredicate),这对应万象词库里
// 只为真实存在的 拼音;辅码 派生拼写。辅码不分大小写,和万象的大写变体一样。
//
// 缩写(Aux2Abbrev、Initial)对应 librime 的 kAbbreviation:只要存在一条全由非缩写拼写组成、
// 走到输入末尾的路径,所有缩写边就被剪掉(syllabifier.cc 的 stale edge 清理)。所以 uiab 单独
// 敲时能当一个带两位辅码的字,放进句子里就会让位给 ui'ab 这类正常切分,要在句中用四码必须
// 补 /。这正是万象的行为,不是这里的简化。
namespace direct_helpcode
{
enum class SpellingKind
{
Plain,
Aux1,
Aux2Slash,
Aux2Abbrev,
Initial,
};
struct SyllableSpelling
{
// 在输入串里的范围 [begin, end),含辅码与 /。
std::size_t begin = 0;
std::size_t end = 0;
// 小写的双拼码:两键,Initial 是一键。
std::string code;
// 全拼音节;Initial 是声母。
std::string quanpin;
// 小写辅码,0 表示没有。
char first = 0;
char second = 0;
SpellingKind kind = SpellingKind::Plain;
bool is_abbreviation() const
{
return kind == SpellingKind::Aux2Abbrev || kind == SpellingKind::Initial;
}
bool has_aux() const
{
return first != 0;
}
};
// 全拼音节 quanpin 下有没有字的辅码以 first(second 非 0 时为 first+second)开头。
using AuxPredicate = std::function<bool(const std::string &quanpin, char first, char second)>;
struct SpellingGraph
{
std::size_t size = 0;
// edges[pos]:从 pos 开始的拼写。只保留落在某条从 0 到 size 的完整路径上的边。
std::vector<std::vector<SyllableSpelling>> edges;
// skip[pos]:pos 上是分隔符,不出字,直接走到 pos + 1。手动分隔符 ' 总是;/ 与 ; 只在
// 没有它们就切不通时才当分隔符兜底。
std::vector<bool> skip;
bool empty() const
{
return edges.empty();
}
};
// 走不通时返回空图。
SpellingGraph build_spelling_graph(const std::string &typed, const ShuangpinProfile &profile,
const AuxPredicate &has_aux);
// 下一个出字的位置:跳过 pos 起连续的分隔符。
std::size_t next_spelling_position(const SpellingGraph &graph, std::size_t pos);
// 图里只有一条完整切分时返回它:没有可比的切法,不必整句解码。有零条或多条时返回 false。
bool single_path(const SpellingGraph &graph, std::vector<SyllableSpelling> &path);
} // namespace direct_helpcode