Files
Lu Fan(SonnyCalcr) 53ee180ec3 feat(engine): 直接辅助码句中四码可用第二位辅码大写结束 (#630)
直接辅助码的四码在句中原来只能补 / 结束(uiab/),现在也可以把第二位辅码敲成大写(uiaB)。
设置页「直接辅助码句中四码标记」两个勾选框可多选、至少留一个,默认只勾 /。

- 引擎:拼写图新增 Aux2Upper(非缩写)。开着大写标记时大写字母只能当第二位辅码,
  走不通再退回不分大小写的旧规则,第一位辅码敲大写(uiAuiQ)照常可用。/ 的收键受勾选控制。
- 协议:DirectHelpcodeChanged 载荷改为 "0"/"1"/"2"(2 = 开着但 / 不是编码键),
  TSF 据此决定吃不吃 /。
- 配置:新增 helpcode.shuangpin_direct_helpcode_slash / _uppercase,同步写入出厂模板、
  工作配置和两个设置宿主的读写映射。
2026-10-05 20:43:02 +08:00

91 lines
3.7 KiB
C++

#pragma once
#include "direct_lattice.h"
#include "../common/helpcode_utils.h"
#include "../core/query_request.h"
#include <array>
#include <functional>
#include <optional>
#include <string>
#include <utility>
#include <unordered_map>
#include <unordered_set>
#include <vector>
// 双拼直接辅助码的入口:把用户敲的原串(uiauiq)整句解码,选出切分,再把请求改写成句中辅助码
// 的形状(ui'ui + 每个音节上的约束),之后的查词、整句、选词推进、预编辑全部复用句中辅助码那条
// 已有的路径。规则见 spelling_graph.h,开关关着时这里一行都不会跑。
namespace direct_helpcode
{
// 全拼读音 + 单字,词库里所有单字行,建辅码索引用。
using SingleCharRows = std::vector<std::pair<std::string, std::string>>;
struct ResolveContext
{
SpanLookup lookup;
// 一次取出词库里全部单字行。为空时退回按音节逐个查。
std::function<SingleCharRows()> single_char_rows;
// 当前辅助码方案的码表;为空时没有辅码边,整串按普通双拼解。
const HelpcodeUtils::Keymap *keymap = nullptr;
DecodeOptions options;
};
class Resolver
{
public:
explicit Resolver(const ShuangpinProfile &profile);
// 改写了请求返回 true。选中的切分里没有辅码、和普通双拼切得一样时不改写,那时请求本来就对。
bool resolve(QueryRequest &request, const ResolveContext &context);
// 上一次 resolve 顺带解出的最优整句;只有一条切分(没解码)或路径不完整时为空。下一次 resolve 前有效。
const DecodedPath *resolved_sentence() const
{
return last_sentence_;
}
// 词库或整句打分选项变了,查词与解码结果作废。辅码索引只随码表变:它只依赖单字读音和码表,
// 用户造词几乎不会新增单字,选词调频时不必重建。
void reset_cache();
private:
struct SyllableAux
{
std::array<bool, 26> first{};
std::unordered_set<std::string> pairs;
};
struct Resolution
{
std::vector<SyllableSpelling> spellings;
std::optional<DecodedPath> sentence;
};
void build_aux_index(const ResolveContext &context);
bool has_aux(const std::string &quanpin, char first, char second, const ResolveContext &context);
const std::vector<quanpin::LatticeLexeme> &span_rows(const quanpin::Segments &span, bool constrained,
const ResolveContext &context);
const ShuangpinProfile profile_;
const HelpcodeUtils::Keymap *indexed_keymap_ = nullptr;
bool aux_index_built_ = false;
std::unordered_map<std::string, SyllableAux> aux_index_;
// 跨按键复用的跨度查询:每敲一个键整串重新解码,前面那些跨度的行没有变。
std::unordered_map<std::string, std::vector<quanpin::LatticeLexeme>> span_cache_;
// 跨按键复用的词边:见 WordEdgeMemo。
WordEdgeMemo word_memo_;
// 搭配分(尾窗 + 词 + 是否句尾 → 分数),整句打分选项变了随 reset_cache 一起清。
std::unordered_map<std::string, double> collocation_memo_;
std::string collocation_key_;
// resolution_cache_ 里的切分是按这组四码标记解出来的。
SpellingOptions spelling_options_;
std::unordered_map<std::string, Resolution> resolution_cache_;
const DecodedPath *last_sentence_ = nullptr;
};
// 按选中的切分改写请求,纯函数,单测直接用。typed 是原串(保留大小写)。
void apply_spellings(QueryRequest &request, const std::string &typed, const std::vector<SyllableSpelling> &spellings,
const ShuangpinProfile &profile);
} // namespace direct_helpcode