hanzi-chai 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/affine.d.ts +8 -0
  2. package/dist/affine.js +153 -0
  3. package/dist/assembly.d.ts +63 -0
  4. package/dist/assembly.js +286 -0
  5. package/dist/bezier.d.ts +74 -0
  6. package/dist/bezier.js +140 -0
  7. package/dist/classifier.d.ts +109 -0
  8. package/dist/classifier.js +108 -0
  9. package/dist/component.d.ts +115 -0
  10. package/dist/component.js +278 -0
  11. package/dist/compound.d.ts +64 -0
  12. package/dist/compound.js +652 -0
  13. package/dist/config.d.ts +236 -0
  14. package/dist/config.js +48 -0
  15. package/dist/data/cjk.txt +20902 -0
  16. package/dist/data/data/cjk.txt +20902 -0
  17. package/dist/data/data/dictionary.txt +69429 -0
  18. package/dist/data/data/frequency.txt +263137 -0
  19. package/dist/data/data/key_distribution.txt +46 -0
  20. package/dist/data/data/pair_equivalence.txt +2116 -0
  21. package/dist/data/data/repertoire.json.deflate +0 -0
  22. package/dist/data/data/tygf.txt +8105 -0
  23. package/dist/data/dictionary.txt +69429 -0
  24. package/dist/data/frequency.txt +263137 -0
  25. package/dist/data/key_distribution.txt +46 -0
  26. package/dist/data/pair_equivalence.txt +2116 -0
  27. package/dist/data/repertoire.json.deflate +0 -0
  28. package/dist/data/tygf.txt +8105 -0
  29. package/dist/data.d.ts +195 -0
  30. package/dist/data.js +18 -0
  31. package/dist/degenerator.d.ts +21 -0
  32. package/dist/degenerator.js +134 -0
  33. package/dist/element.d.ts +56 -0
  34. package/dist/element.js +225 -0
  35. package/dist/equivalence.d.ts +21 -0
  36. package/dist/equivalence.js +74 -0
  37. package/dist/index.d.ts +45 -0
  38. package/dist/index.js +126 -0
  39. package/dist/index.mjs +3553 -0
  40. package/dist/mathjs.d.ts +10 -0
  41. package/dist/mathjs.js +9 -0
  42. package/dist/repertoire.d.ts +75 -0
  43. package/dist/repertoire.js +406 -0
  44. package/dist/selector.d.ts +110 -0
  45. package/dist/selector.js +310 -0
  46. package/dist/topology.d.ts +41 -0
  47. package/dist/topology.js +209 -0
  48. package/dist/transformer.d.ts +18 -0
  49. package/dist/transformer.js +111 -0
  50. package/dist/utils.d.ts +107 -0
  51. package/dist/utils.js +546 -0
  52. package/package.json +34 -0
@@ -0,0 +1,74 @@
1
+ import { range } from "lodash-es";
2
+ // partition the group into subgroups according to binary equivalence relation
3
+ // using DFS algorithm
4
+ export function partition({ group, relation }) {
5
+ const visited = new Set();
6
+ const result = [];
7
+ for (const v of group) {
8
+ if (visited.has(v))
9
+ continue;
10
+ const subgroup = new Set();
11
+ const stack = [v];
12
+ while (stack.length > 0) {
13
+ const u = stack.pop();
14
+ visited.add(u);
15
+ subgroup.add(u);
16
+ for (const w of group) {
17
+ if (visited.has(w))
18
+ continue;
19
+ if (relation(u, w))
20
+ stack.push(w);
21
+ }
22
+ }
23
+ result.push(subgroup);
24
+ }
25
+ return result;
26
+ }
27
+ const isDifferentHand = (p) => {
28
+ if (p.initial === p.final)
29
+ return false;
30
+ return (p.initial < 20 && p.final >= 15) || (p.initial >= 15 && p.final < 20);
31
+ };
32
+ const isSameHand = (p1, p2) => {
33
+ const numbers = [p1.initial, p1.final, p2.initial, p2.final];
34
+ return numbers.every((n) => n < 15) || numbers.every((n) => n >= 20);
35
+ };
36
+ const reflect = (n) => {
37
+ const [col, row] = [Math.floor(n / 5), n % 5];
38
+ return (6 - col) * 5 + row;
39
+ };
40
+ export const distance = (p) => {
41
+ if (isDifferentHand(p))
42
+ return -1;
43
+ const [x1, y1] = [Math.floor(p.initial / 5), p.initial % 5];
44
+ const [x2, y2] = [Math.floor(p.final / 5), p.final % 5];
45
+ return (x1 - x2) ** 2 + (y1 - y2) ** 2;
46
+ };
47
+ export const displacement = (p) => {
48
+ const [x1, y1] = [Math.floor(p.initial / 5), p.initial % 5];
49
+ const [x2, y2] = [Math.floor(p.final / 5), p.final % 5];
50
+ return [x2 - x1, y2 - y1];
51
+ };
52
+ export const 手机五行七列 = {
53
+ group: new Set(range(35).flatMap((n) => range(35).map((m) => ({ initial: n, final: m })))),
54
+ relation: (p1, p2) => {
55
+ // 异指连击当量相同
56
+ if (isDifferentHand(p1) && isDifferentHand(p2))
57
+ return true;
58
+ // 同键连击当量相同
59
+ if (p1.initial === p1.final && p2.initial === p2.final)
60
+ return true;
61
+ // 时间反演
62
+ if (p1.initial === p2.final && p1.final === p2.initial)
63
+ return true;
64
+ // 空间镜像
65
+ if (reflect(p1.initial) === p2.initial && reflect(p1.final) === p2.final)
66
+ return true;
67
+ // 空间平移(同手)
68
+ const [dx1, dy1] = displacement(p1);
69
+ const [dx2, dy2] = displacement(p2);
70
+ if (isSameHand(p1, p2) && dx1 === dx2 && dy1 === dy2)
71
+ return true;
72
+ return false;
73
+ },
74
+ };
@@ -0,0 +1,45 @@
1
+ export * from "./affine.js";
2
+ export * from "./element.js";
3
+ export * from "./bezier.js";
4
+ export * from "./topology.js";
5
+ export * from "./data.js";
6
+ export * from "./config.js";
7
+ export * from "./classifier.js";
8
+ export * from "./repertoire.js";
9
+ export * from "./degenerator.js";
10
+ export * from "./selector.js";
11
+ export * from "./assembly.js";
12
+ export * from "./component.js";
13
+ export * from "./compound.js";
14
+ export * from "./utils.js";
15
+ export * from "./mathjs.js";
16
+ export * from "./transformer.js";
17
+ import { PrimitiveCharacter, PrimitiveRepertoire, Repertoire } from "./data.js";
18
+ import { Dictionary, Frequency } from "./utils.js";
19
+ import { Config } from "./config.js";
20
+ import { AnalysisConfig } from "./repertoire.js";
21
+ export interface Item {
22
+ id: number;
23
+ name: string;
24
+ price: number;
25
+ }
26
+ interface Model {
27
+ unicode: number;
28
+ tygf: 0 | 1 | 2 | 3;
29
+ gb2312: 0 | 1 | 2;
30
+ readings: string;
31
+ glyphs: string;
32
+ name: string | null;
33
+ gf0014_id: number | null;
34
+ gf3001_id: number | null;
35
+ ambiguous: 0 | 1;
36
+ }
37
+ export declare function fromModel(model: Model): PrimitiveCharacter;
38
+ export declare function getPrimitveRepertoire(): PrimitiveRepertoire;
39
+ export declare function getDictionary(): Dictionary;
40
+ export declare function getFrequency(): Frequency;
41
+ export declare function getRepertoire(config: Config): Repertoire;
42
+ export declare function getCharacters(config: Config, repertoire: Repertoire): string[];
43
+ export declare function getAnalysisConfig(config: Config, repertoire: Repertoire): AnalysisConfig;
44
+ export declare function getAnalysisResult(config: Config, repertoire: Repertoire): import("./repertoire.js").AnalysisResult;
45
+ export declare function getAssemblyResult(config: Config, repertoire: Repertoire): void;
package/dist/index.js ADDED
@@ -0,0 +1,126 @@
1
+ export * from "./affine.js";
2
+ export * from "./element.js";
3
+ export * from "./bezier.js";
4
+ export * from "./topology.js";
5
+ export * from "./data.js";
6
+ export * from "./config.js";
7
+ export * from "./classifier.js";
8
+ export * from "./repertoire.js";
9
+ export * from "./degenerator.js";
10
+ export * from "./selector.js";
11
+ export * from "./assembly.js";
12
+ export * from "./component.js";
13
+ export * from "./compound.js";
14
+ export * from "./utils.js";
15
+ export * from "./mathjs.js";
16
+ export * from "./transformer.js";
17
+ import { readFileSync } from "node:fs";
18
+ import path from "node:path";
19
+ import { fileURLToPath } from "node:url";
20
+ import Pako from "pako";
21
+ import { characterSetFilters, listToObject } from "./utils.js";
22
+ import { analysis, determine } from "./repertoire.js";
23
+ import { 应用变换器 } from "./transformer.js";
24
+ import { assemble } from "./assembly.js";
25
+ // ESM 中模拟 __dirname
26
+ const __filename = fileURLToPath(import.meta.url);
27
+ const __dirname = path.dirname(__filename);
28
+ const codeToChar = (code) => String.fromCodePoint(code);
29
+ const glyphForward = (c) => {
30
+ if (c.type === "basic_component") {
31
+ return c;
32
+ }
33
+ else if (c.type === "derived_component" || c.type === "identity") {
34
+ return { ...c, source: codeToChar(c.source) };
35
+ }
36
+ else {
37
+ return { ...c, operandList: c.operandList.map(codeToChar) };
38
+ }
39
+ };
40
+ export function fromModel(model) {
41
+ return {
42
+ ...model,
43
+ readings: JSON.parse(model.readings),
44
+ glyphs: JSON.parse(model.glyphs).map(glyphForward),
45
+ ambiguous: model.ambiguous === 1,
46
+ };
47
+ }
48
+ export function getPrimitveRepertoire() {
49
+ const filePath = path.join(__dirname, "data", "repertoire.json.deflate");
50
+ const compressed = readFileSync(filePath);
51
+ const decompressed = Pako.inflate(compressed, { to: "string" });
52
+ const raw = JSON.parse(decompressed).map(fromModel);
53
+ const primitiveRepertoire = listToObject(raw);
54
+ return primitiveRepertoire;
55
+ }
56
+ export function getDictionary() {
57
+ const filePath = path.join(__dirname, "data", "dictionary.txt");
58
+ const raw = readFileSync(filePath, "utf-8");
59
+ return raw.trim().split("\n").map((line) => {
60
+ const [key, value] = line.split("\t");
61
+ return [key, value];
62
+ });
63
+ }
64
+ export function getFrequency() {
65
+ const filePath = path.join(__dirname, "data", "frequency.txt");
66
+ const raw = readFileSync(filePath, "utf-8");
67
+ return Object.fromEntries(raw.trim().split("\n").map((line) => {
68
+ const [char, freq] = line.split("\t");
69
+ return [char, Number(freq)];
70
+ }));
71
+ }
72
+ export function getRepertoire(config) {
73
+ const primitiveRepertoire = getPrimitveRepertoire();
74
+ const userRepertoire = config.data?.repertoire ?? {};
75
+ const allRepertoire = { ...primitiveRepertoire, ...userRepertoire };
76
+ const customGlyph = config.data?.glyph_customization ?? {};
77
+ const customReadings = config.data?.reading_customization ?? {};
78
+ const tags = config.data?.tags ?? [];
79
+ let determined = determine(allRepertoire, customGlyph, customReadings, tags);
80
+ const transformers = config.data?.transformers ?? [];
81
+ for (const transformer of transformers) {
82
+ determined = 应用变换器(determined, transformer);
83
+ }
84
+ return determined;
85
+ }
86
+ export function getCharacters(config, repertoire) {
87
+ const characterSet = config.data?.character_set ?? "minimal";
88
+ const filter = characterSetFilters[characterSet];
89
+ const characters = Object.entries(repertoire)
90
+ .filter(([k, v]) => filter(k, v))
91
+ .map(([k]) => k);
92
+ return characters;
93
+ }
94
+ export function getAnalysisConfig(config, repertoire) {
95
+ const mapping = config.form.mapping;
96
+ const mappingSpace = config.form.mapping_space ?? {};
97
+ const optionalRoots = new Set();
98
+ for (const [key, value] of Object.entries(mappingSpace)) {
99
+ if (value.some((x) => x.value == null) || mapping[key] === undefined) {
100
+ optionalRoots.add(key);
101
+ }
102
+ }
103
+ const analysis = config.analysis ?? {};
104
+ const roots = new Map(Object.entries(mapping).filter(([x]) => repertoire[x]));
105
+ return {
106
+ analysis,
107
+ roots,
108
+ optionalRoots,
109
+ };
110
+ }
111
+ export function getAnalysisResult(config, repertoire) {
112
+ const analysisConfig = getAnalysisConfig(config, repertoire);
113
+ const characters = getCharacters(config, repertoire);
114
+ return analysis(repertoire, analysisConfig, characters);
115
+ }
116
+ export function getAssemblyResult(config, repertoire) {
117
+ const characters = getCharacters(config, repertoire);
118
+ const analysisResult = getAnalysisResult(config, repertoire);
119
+ const assembleConfig = {
120
+ algebra: config.algebra ?? {},
121
+ encoder: config.encoder ?? {},
122
+ keyboard: config.form ?? {},
123
+ priority: config.encoder?.priority_short_codes ?? [],
124
+ };
125
+ assemble(repertoire, assembleConfig, characters, getDictionary(), new Map(Object.entries(getFrequency())), analysisResult, {});
126
+ }