@kensio/pinyinjs 0.1.0-beta.0 → 1.0.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.
- package/CHANGELOG.md +87 -0
- package/NOTICE +7 -0
- package/README.md +144 -19
- package/data/full.entries +13400 -13400
- package/data/manifest.json +4 -4
- package/data/standard.entries +2492 -2492
- package/dist/cli/arguments.d.ts +67 -0
- package/dist/cli/arguments.d.ts.map +1 -1
- package/dist/cli/arguments.js +79 -0
- package/dist/cli/arguments.js.map +1 -1
- package/dist/cli/colour.d.ts +77 -0
- package/dist/cli/colour.d.ts.map +1 -0
- package/dist/cli/colour.js +117 -0
- package/dist/cli/colour.js.map +1 -0
- package/dist/cli/commands.d.ts +49 -1
- package/dist/cli/commands.d.ts.map +1 -1
- package/dist/cli/commands.js +404 -42
- package/dist/cli/commands.js.map +1 -1
- package/dist/cli/environment.d.ts.map +1 -1
- package/dist/cli/environment.js +20 -0
- package/dist/cli/environment.js.map +1 -1
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +43 -16
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/run.d.ts +11 -0
- package/dist/cli/run.d.ts.map +1 -1
- package/dist/cli/run.js +4 -2
- package/dist/cli/run.js.map +1 -1
- package/dist/decode/convert.d.ts +20 -0
- package/dist/decode/convert.d.ts.map +1 -1
- package/dist/decode/convert.js +170 -12
- package/dist/decode/convert.js.map +1 -1
- package/dist/decode/decode.d.ts +3 -2
- package/dist/decode/decode.d.ts.map +1 -1
- package/dist/decode/decode.js +17 -4
- package/dist/decode/decode.js.map +1 -1
- package/dist/decode/reading-rules.d.ts +56 -0
- package/dist/decode/reading-rules.d.ts.map +1 -0
- package/dist/decode/reading-rules.js +107 -0
- package/dist/decode/reading-rules.js.map +1 -0
- package/dist/decode/rules.d.ts +66 -0
- package/dist/decode/rules.d.ts.map +1 -0
- package/dist/decode/rules.js +138 -0
- package/dist/decode/rules.js.map +1 -0
- package/dist/decode/sandhi.d.ts +1 -1
- package/dist/decode/sandhi.d.ts.map +1 -1
- package/dist/decode/sandhi.js +60 -1
- package/dist/decode/sandhi.js.map +1 -1
- package/dist/decode/word.d.ts +18 -0
- package/dist/decode/word.d.ts.map +1 -1
- package/dist/dictionary/artifact.d.ts.map +1 -1
- package/dist/dictionary/artifact.js +28 -1
- package/dist/dictionary/artifact.js.map +1 -1
- package/dist/dictionary/dictionary.d.ts +9 -0
- package/dist/dictionary/dictionary.d.ts.map +1 -1
- package/dist/dictionary/dictionary.js +7 -0
- package/dist/dictionary/dictionary.js.map +1 -1
- package/dist/dictionary/entry.d.ts +12 -0
- package/dist/dictionary/entry.d.ts.map +1 -1
- package/dist/dictionary/entry.js.map +1 -1
- package/dist/dictionary/merge.d.ts +3 -1
- package/dist/dictionary/merge.d.ts.map +1 -1
- package/dist/dictionary/merge.js +19 -1
- package/dist/dictionary/merge.js.map +1 -1
- package/dist/format/transcription.d.ts +52 -0
- package/dist/format/transcription.d.ts.map +1 -0
- package/dist/format/transcription.js +88 -0
- package/dist/format/transcription.js.map +1 -0
- package/dist/index.d.ts +24 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -1
- package/dist/index.js.map +1 -1
- package/dist/numerals/cardinal.d.ts +39 -0
- package/dist/numerals/cardinal.d.ts.map +1 -0
- package/dist/numerals/cardinal.js +111 -0
- package/dist/numerals/cardinal.js.map +1 -0
- package/dist/numerals/characters.d.ts +31 -0
- package/dist/numerals/characters.d.ts.map +1 -0
- package/dist/numerals/characters.js +80 -0
- package/dist/numerals/characters.js.map +1 -0
- package/dist/numerals/numerals.d.ts +76 -0
- package/dist/numerals/numerals.d.ts.map +1 -0
- package/dist/numerals/numerals.js +119 -0
- package/dist/numerals/numerals.js.map +1 -0
- package/dist/numerals/text.d.ts +52 -0
- package/dist/numerals/text.d.ts.map +1 -0
- package/dist/numerals/text.js +248 -0
- package/dist/numerals/text.js.map +1 -0
- package/dist/orthography/grouping.d.ts +56 -11
- package/dist/orthography/grouping.d.ts.map +1 -1
- package/dist/orthography/grouping.js +109 -35
- package/dist/orthography/grouping.js.map +1 -1
- package/dist/orthography/idiom-list.d.ts +56 -0
- package/dist/orthography/idiom-list.d.ts.map +1 -0
- package/dist/orthography/idiom-list.js +296 -0
- package/dist/orthography/idiom-list.js.map +1 -0
- package/dist/orthography/idioms.d.ts +18 -0
- package/dist/orthography/idioms.d.ts.map +1 -0
- package/dist/orthography/idioms.js +22 -0
- package/dist/orthography/idioms.js.map +1 -0
- package/dist/orthography/reduplication.d.ts +52 -0
- package/dist/orthography/reduplication.d.ts.map +1 -0
- package/dist/orthography/reduplication.js +99 -0
- package/dist/orthography/reduplication.js.map +1 -0
- package/dist/orthography/rule.d.ts +50 -0
- package/dist/orthography/rule.d.ts.map +1 -0
- package/dist/orthography/rule.js +101 -0
- package/dist/orthography/rule.js.map +1 -0
- package/dist/sources/cedict.d.ts +23 -0
- package/dist/sources/cedict.d.ts.map +1 -1
- package/dist/sources/cedict.js +28 -0
- package/dist/sources/cedict.js.map +1 -1
- package/dist/syllable/syllable.d.ts +1 -1
- package/dist/syllable/syllable.d.ts.map +1 -1
- package/dist/syllable/syllable.js +2 -37
- package/dist/syllable/syllable.js.map +1 -1
- package/dist/tone/tone-mark.d.ts +23 -0
- package/dist/tone/tone-mark.d.ts.map +1 -1
- package/dist/tone/tone-mark.js +49 -0
- package/dist/tone/tone-mark.js.map +1 -1
- package/dist/transcription/bopomofo.d.ts +46 -0
- package/dist/transcription/bopomofo.d.ts.map +1 -0
- package/dist/transcription/bopomofo.js +371 -0
- package/dist/transcription/bopomofo.js.map +1 -0
- package/dist/transcription/gwoyeu.d.ts +32 -0
- package/dist/transcription/gwoyeu.d.ts.map +1 -0
- package/dist/transcription/gwoyeu.js +491 -0
- package/dist/transcription/gwoyeu.js.map +1 -0
- package/dist/transcription/ipa.d.ts +40 -0
- package/dist/transcription/ipa.d.ts.map +1 -0
- package/dist/transcription/ipa.js +221 -0
- package/dist/transcription/ipa.js.map +1 -0
- package/dist/transcription/spelling-index.d.ts +23 -0
- package/dist/transcription/spelling-index.d.ts.map +1 -0
- package/dist/transcription/spelling-index.js +61 -0
- package/dist/transcription/spelling-index.js.map +1 -0
- package/dist/transcription/wade-giles.d.ts +108 -0
- package/dist/transcription/wade-giles.d.ts.map +1 -0
- package/dist/transcription/wade-giles.js +656 -0
- package/dist/transcription/wade-giles.js.map +1 -0
- package/dist/transcription/yale.d.ts +43 -0
- package/dist/transcription/yale.d.ts.map +1 -0
- package/dist/transcription/yale.js +242 -0
- package/dist/transcription/yale.js.map +1 -0
- package/package.json +9 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decode.js","sourceRoot":"","sources":["../../src/decode/decode.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"decode.js","sourceRoot":"","sources":["../../src/decode/decode.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { type EdgeRule } from "./rules.js";
|
|
2
|
+
/**
|
|
3
|
+
* 得 read as `děi` where it is a modal rather than a particle.
|
|
4
|
+
*
|
|
5
|
+
* One character, three readings, and the dictionary can only carry a default:
|
|
6
|
+
* 得 is stored `de` — the structural particle, which is far the commonest — with
|
|
7
|
+
* `dé` and `děi` as alternates. Nothing in the cost model can prefer an
|
|
8
|
+
* alternate at a position no word covers, so 我得走了 came out `wǒ de zǒule`
|
|
9
|
+
* and every other modal 得 with it. This is the case ROADMAP.md was waiting for
|
|
10
|
+
* before building stage 4: neither harness could see it, since the gold corpus
|
|
11
|
+
* had only 觉得 and CPP's 40 得 cases are labelled `dé` or `de` and never `děi`.
|
|
12
|
+
*
|
|
13
|
+
* The context is what separates the three, and only one side of it carries
|
|
14
|
+
* information. The particle 得 always follows the verb or adjective it attaches
|
|
15
|
+
* to (说得好, 跑得快, 累得要命), so a 得 with a *pronoun, adverb or time word*
|
|
16
|
+
* in front of it is not that particle. Requiring a verb phrase after it as well
|
|
17
|
+
* keeps 得了感冒 and 得了奖 — `dé`, and a real reading of the same character —
|
|
18
|
+
* out of it.
|
|
19
|
+
*
|
|
20
|
+
* Conditioning on what precedes rather than on what follows was measured, not
|
|
21
|
+
* assumed: "the word before is not a verb" fires 309 times over 88,866 lines of
|
|
22
|
+
* Tatoeba and zh.wikipedia and is wrong about four times in five, because
|
|
23
|
+
* jieba tags 下 as `f`, 学 as `n` and 飞 as nothing at all, and 雨下得很大 is a
|
|
24
|
+
* particle whatever the tag says. Naming the small closed set of things that
|
|
25
|
+
* can precede a modal is the same rule from the other side, and over the same
|
|
26
|
+
* text it fires 126 times and is right 122: the four misses are literary 得
|
|
27
|
+
* read `dé` after an adverb — 未必得喜悦, 暂得于己, 仅得约, 未得迁还家乡 —
|
|
28
|
+
* which nothing short of semantics separates from 必须得承认.
|
|
29
|
+
*/
|
|
30
|
+
export declare const MODAL_DE: EdgeRule;
|
|
31
|
+
/**
|
|
32
|
+
* 儿 does not stand on its own where the dictionary attests the 儿化.
|
|
33
|
+
*
|
|
34
|
+
* 儿化 is a per-word dictionary fact taken from CC-CEDICT's explicit `r5`
|
|
35
|
+
* token, and 2,009 of the 2,067 keys ending in 儿 carry it. What that leaves is
|
|
36
|
+
* an edge: 这边儿, 上边儿 and 旁边儿 are all listed and 那边儿 is not, so
|
|
37
|
+
* 我得跑到那边儿去 read the 儿 as a syllable of its own — `nàbian ér` — and the
|
|
38
|
+
* decode was choosing between 那边 plus 儿 and 那 plus 边儿 on frequency alone.
|
|
39
|
+
*
|
|
40
|
+
* This forbids the bare 儿 edge when the character in front of it makes an
|
|
41
|
+
* attested 儿化 word, so the only paths left are the ones that absorb it. That
|
|
42
|
+
* asserts nothing the dictionary does not already say — 边儿 is `biānr` because
|
|
43
|
+
* CC-CEDICT says so — which is what separates it from synthesising 儿化 with a
|
|
44
|
+
* suffix rule, the thing ORTHOGRAPHY.md rejects and the old project got wrong.
|
|
45
|
+
*
|
|
46
|
+
* Measured over the same 88,866 lines it fires 7 times, and all 7 are right:
|
|
47
|
+
* 照片儿, 出门儿, 热点儿, 辣味儿, 晚会儿, 针管儿, 碍事儿. It is deliberately
|
|
48
|
+
* silent on the 20 bare 儿 with no attested 儿化 behind them, which are 马儿,
|
|
49
|
+
* 门铃儿 and a row of Mongol names transliterated with 儿.
|
|
50
|
+
*/
|
|
51
|
+
export declare const ATTESTED_ERHUA: EdgeRule;
|
|
52
|
+
/**
|
|
53
|
+
* The rules the lattice decode applies, in order.
|
|
54
|
+
*/
|
|
55
|
+
export declare const READING_RULES: readonly EdgeRule[];
|
|
56
|
+
//# sourceMappingURL=reading-rules.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reading-rules.d.ts","sourceRoot":"","sources":["../../src/decode/reading-rules.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,QAAQ,EAId,MAAM,YAAY,CAAC;AAgCpB;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,QAAQ,EAAE,QActB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,cAAc,EAAE,QAY5B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,SAAS,QAAQ,EAA+B,CAAC"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { tagOf, wordEndingAt, wordStartingAt, } from "./rules.js";
|
|
2
|
+
/**
|
|
3
|
+
* Whether a syllable is `děi`, the modal reading of 得.
|
|
4
|
+
*
|
|
5
|
+
* Compared structurally rather than by spelling it out, since a syllable is
|
|
6
|
+
* stored as its parts and writing one back is the formatting stage's job.
|
|
7
|
+
*/
|
|
8
|
+
function isDei(syllable) {
|
|
9
|
+
return (syllable?.initial === "d" && syllable.final === "ei" && syllable.tone === 3);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* What stands in front of a modal 得: a subject, an adverb, or a time word.
|
|
13
|
+
*
|
|
14
|
+
* 我得走, 你就得去, 我今天得走. The particle 得 cannot follow any of these,
|
|
15
|
+
* because it attaches to the predicate it modifies — which is exactly what
|
|
16
|
+
* makes this the discriminating side of the context.
|
|
17
|
+
*/
|
|
18
|
+
const SUBJECT_TAGS = new Set(["r", "d", "t"]);
|
|
19
|
+
/**
|
|
20
|
+
* What follows a modal 得: the verb phrase it governs.
|
|
21
|
+
*
|
|
22
|
+
* Prepositions and adverbs are in because 我得在八月, 我得先走 and 我得快点 are
|
|
23
|
+
* all modal, and what follows the 得 in each is the front of a verb phrase
|
|
24
|
+
* rather than a verb.
|
|
25
|
+
*/
|
|
26
|
+
const GOVERNED_TAGS = /^(?:v|p|d|a)/u;
|
|
27
|
+
/**
|
|
28
|
+
* 得 read as `děi` where it is a modal rather than a particle.
|
|
29
|
+
*
|
|
30
|
+
* One character, three readings, and the dictionary can only carry a default:
|
|
31
|
+
* 得 is stored `de` — the structural particle, which is far the commonest — with
|
|
32
|
+
* `dé` and `děi` as alternates. Nothing in the cost model can prefer an
|
|
33
|
+
* alternate at a position no word covers, so 我得走了 came out `wǒ de zǒule`
|
|
34
|
+
* and every other modal 得 with it. This is the case ROADMAP.md was waiting for
|
|
35
|
+
* before building stage 4: neither harness could see it, since the gold corpus
|
|
36
|
+
* had only 觉得 and CPP's 40 得 cases are labelled `dé` or `de` and never `děi`.
|
|
37
|
+
*
|
|
38
|
+
* The context is what separates the three, and only one side of it carries
|
|
39
|
+
* information. The particle 得 always follows the verb or adjective it attaches
|
|
40
|
+
* to (说得好, 跑得快, 累得要命), so a 得 with a *pronoun, adverb or time word*
|
|
41
|
+
* in front of it is not that particle. Requiring a verb phrase after it as well
|
|
42
|
+
* keeps 得了感冒 and 得了奖 — `dé`, and a real reading of the same character —
|
|
43
|
+
* out of it.
|
|
44
|
+
*
|
|
45
|
+
* Conditioning on what precedes rather than on what follows was measured, not
|
|
46
|
+
* assumed: "the word before is not a verb" fires 309 times over 88,866 lines of
|
|
47
|
+
* Tatoeba and zh.wikipedia and is wrong about four times in five, because
|
|
48
|
+
* jieba tags 下 as `f`, 学 as `n` and 飞 as nothing at all, and 雨下得很大 is a
|
|
49
|
+
* particle whatever the tag says. Naming the small closed set of things that
|
|
50
|
+
* can precede a modal is the same rule from the other side, and over the same
|
|
51
|
+
* text it fires 126 times and is right 122: the four misses are literary 得
|
|
52
|
+
* read `dé` after an adverb — 未必得喜悦, 暂得于己, 仅得约, 未得迁还家乡 —
|
|
53
|
+
* which nothing short of semantics separates from 必须得承认.
|
|
54
|
+
*/
|
|
55
|
+
export const MODAL_DE = {
|
|
56
|
+
name: "modal-de",
|
|
57
|
+
verdictFor: (context) => {
|
|
58
|
+
const { edge } = context;
|
|
59
|
+
if (edge.text !== "得" || !isDei(edge.reading[0])) {
|
|
60
|
+
return "keep";
|
|
61
|
+
}
|
|
62
|
+
const before = wordEndingAt(context, edge.from);
|
|
63
|
+
const after = wordStartingAt(context, edge.to);
|
|
64
|
+
return SUBJECT_TAGS.has(tagOf(context, before)) &&
|
|
65
|
+
GOVERNED_TAGS.test(tagOf(context, after))
|
|
66
|
+
? "force"
|
|
67
|
+
: "keep";
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* 儿 does not stand on its own where the dictionary attests the 儿化.
|
|
72
|
+
*
|
|
73
|
+
* 儿化 is a per-word dictionary fact taken from CC-CEDICT's explicit `r5`
|
|
74
|
+
* token, and 2,009 of the 2,067 keys ending in 儿 carry it. What that leaves is
|
|
75
|
+
* an edge: 这边儿, 上边儿 and 旁边儿 are all listed and 那边儿 is not, so
|
|
76
|
+
* 我得跑到那边儿去 read the 儿 as a syllable of its own — `nàbian ér` — and the
|
|
77
|
+
* decode was choosing between 那边 plus 儿 and 那 plus 边儿 on frequency alone.
|
|
78
|
+
*
|
|
79
|
+
* This forbids the bare 儿 edge when the character in front of it makes an
|
|
80
|
+
* attested 儿化 word, so the only paths left are the ones that absorb it. That
|
|
81
|
+
* asserts nothing the dictionary does not already say — 边儿 is `biānr` because
|
|
82
|
+
* CC-CEDICT says so — which is what separates it from synthesising 儿化 with a
|
|
83
|
+
* suffix rule, the thing ORTHOGRAPHY.md rejects and the old project got wrong.
|
|
84
|
+
*
|
|
85
|
+
* Measured over the same 88,866 lines it fires 7 times, and all 7 are right:
|
|
86
|
+
* 照片儿, 出门儿, 热点儿, 辣味儿, 晚会儿, 针管儿, 碍事儿. It is deliberately
|
|
87
|
+
* silent on the 20 bare 儿 with no attested 儿化 behind them, which are 马儿,
|
|
88
|
+
* 门铃儿 and a row of Mongol names transliterated with 儿.
|
|
89
|
+
*/
|
|
90
|
+
export const ATTESTED_ERHUA = {
|
|
91
|
+
name: "attested-erhua",
|
|
92
|
+
verdictFor: (context) => {
|
|
93
|
+
const { characters, edge } = context;
|
|
94
|
+
if (edge.text !== "儿" || edge.from === 0) {
|
|
95
|
+
return "keep";
|
|
96
|
+
}
|
|
97
|
+
/* c8 ignore next -- the edge starts inside the run it was built from */
|
|
98
|
+
const absorbed = `${characters[edge.from - 1] ?? ""}儿`;
|
|
99
|
+
const reading = context.dictionary.lookup(absorbed)?.reading;
|
|
100
|
+
return (reading?.at(-1)?.erhua ?? false) ? "forbid" : "keep";
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* The rules the lattice decode applies, in order.
|
|
105
|
+
*/
|
|
106
|
+
export const READING_RULES = [MODAL_DE, ATTESTED_ERHUA];
|
|
107
|
+
//# sourceMappingURL=reading-rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reading-rules.js","sourceRoot":"","sources":["../../src/decode/reading-rules.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,EACL,YAAY,EACZ,cAAc,GACf,MAAM,YAAY,CAAC;AAEpB;;;;;GAKG;AACH,SAAS,KAAK,CAAC,QAA8B;IAC3C,OAAO,CACL,QAAQ,EAAE,OAAO,KAAK,GAAG,IAAI,QAAQ,CAAC,KAAK,KAAK,IAAI,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC,CAC5E,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;AAE9C;;;;;;GAMG;AACH,MAAM,aAAa,GAAG,eAAe,CAAC;AAEtC;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAa;IAChC,IAAI,EAAE,UAAU;IAChB,UAAU,EAAE,CAAC,OAAoB,EAAE,EAAE;QACnC,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC;QACzB,IAAI,IAAI,CAAC,IAAI,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACjD,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAChD,MAAM,KAAK,GAAG,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;QAC/C,OAAO,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC7C,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACzC,CAAC,CAAC,OAAO;YACT,CAAC,CAAC,MAAM,CAAC;IACb,CAAC;CACF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,cAAc,GAAa;IACtC,IAAI,EAAE,gBAAgB;IACtB,UAAU,EAAE,CAAC,OAAoB,EAAE,EAAE;QACnC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC;QACrC,IAAI,IAAI,CAAC,IAAI,KAAK,GAAG,IAAI,IAAI,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACzC,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,wEAAwE;QACxE,MAAM,QAAQ,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC;QACvD,MAAM,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;QAC7D,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC;IAC/D,CAAC;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GAAwB,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { Dictionary } from "../dictionary/dictionary.js";
|
|
2
|
+
import type { Lattice, LatticeEdge } from "./lattice.js";
|
|
3
|
+
/**
|
|
4
|
+
* What a rule can say about one edge.
|
|
5
|
+
*
|
|
6
|
+
* `forbid` takes the edge out of the lattice; `force` takes every *rival* out,
|
|
7
|
+
* meaning every other edge covering exactly the same characters. Forcing settles
|
|
8
|
+
* how a stretch is read without saying anything about how it is segmented, so
|
|
9
|
+
* the words that overlap it are left to the decode.
|
|
10
|
+
*/
|
|
11
|
+
export type EdgeVerdict = "keep" | "forbid" | "force";
|
|
12
|
+
/**
|
|
13
|
+
* What a rule is given to judge an edge by.
|
|
14
|
+
*
|
|
15
|
+
* The characters of the whole run rather than of the edge, because the
|
|
16
|
+
* interesting rules are about context: 得 is `de` after a verb and `děi` before
|
|
17
|
+
* one, and neither is visible from the character on its own.
|
|
18
|
+
*/
|
|
19
|
+
export interface EdgeContext {
|
|
20
|
+
readonly dictionary: Dictionary;
|
|
21
|
+
readonly characters: readonly string[];
|
|
22
|
+
readonly edge: LatticeEdge;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* One typed rule over the lattice's edges — stage 4 of ALGORITHM.md.
|
|
26
|
+
*
|
|
27
|
+
* The old project tweaked its output string with regexes, so its rules ran in
|
|
28
|
+
* an order nobody chose and could not be tested apart from each other. A rule
|
|
29
|
+
* here is a function from one edge to one verdict: it can be read on its own,
|
|
30
|
+
* tested on its own, and measured on its own.
|
|
31
|
+
*/
|
|
32
|
+
export interface EdgeRule {
|
|
33
|
+
readonly name: string;
|
|
34
|
+
readonly verdictFor: (context: EdgeContext) => EdgeVerdict;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The word ending at a position, longest first, or undefined.
|
|
38
|
+
*
|
|
39
|
+
* What a rule needs when it asks about the word *before* an edge. The decode
|
|
40
|
+
* has not run yet, so there is no settled answer; the longest dictionary word
|
|
41
|
+
* ending here is the closest thing available, and it is what the decode will
|
|
42
|
+
* usually choose, since the reading charge prefers fewer words.
|
|
43
|
+
*/
|
|
44
|
+
export declare function wordEndingAt(context: EdgeContext, at: number, longest?: number): string | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* The word starting at a position, longest first, or undefined.
|
|
47
|
+
*/
|
|
48
|
+
export declare function wordStartingAt(context: EdgeContext, at: number, longest?: number): string | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* The part of speech the dictionary gives a word, or the empty string.
|
|
51
|
+
*/
|
|
52
|
+
export declare function tagOf(context: EdgeContext, word: string | undefined): string;
|
|
53
|
+
/**
|
|
54
|
+
* Apply the rules to a lattice, returning the lattice they leave.
|
|
55
|
+
*
|
|
56
|
+
* Stage 4 of the pipeline: the rules run over the built lattice and before any
|
|
57
|
+
* decoding, so what they change is what the decode gets to choose between
|
|
58
|
+
* rather than what it has already chosen. Nothing is rewritten — an edge is
|
|
59
|
+
* kept or it is not — which is what keeps a rule from inventing a reading no
|
|
60
|
+
* source attests.
|
|
61
|
+
*
|
|
62
|
+
* The lattice is returned unchanged if the rules would leave the run with no
|
|
63
|
+
* path through it.
|
|
64
|
+
*/
|
|
65
|
+
export declare function applyEdgeRules(lattice: Lattice, dictionary: Dictionary, rules: readonly EdgeRule[]): Lattice;
|
|
66
|
+
//# sourceMappingURL=rules.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../src/decode/rules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEzD;;;;;;;GAOG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEtD;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;CAC5B;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,WAAW,CAAC;CAC5D;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,WAAW,EACpB,EAAE,EAAE,MAAM,EACV,OAAO,SAAI,GACV,MAAM,GAAG,SAAS,CAYpB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,WAAW,EACpB,EAAE,EAAE,MAAM,EACV,OAAO,SAAI,GACV,MAAM,GAAG,SAAS,CAUpB;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAI5E;AA+DD;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,UAAU,EACtB,KAAK,EAAE,SAAS,QAAQ,EAAE,GACzB,OAAO,CAsCT"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The word ending at a position, longest first, or undefined.
|
|
3
|
+
*
|
|
4
|
+
* What a rule needs when it asks about the word *before* an edge. The decode
|
|
5
|
+
* has not run yet, so there is no settled answer; the longest dictionary word
|
|
6
|
+
* ending here is the closest thing available, and it is what the decode will
|
|
7
|
+
* usually choose, since the reading charge prefers fewer words.
|
|
8
|
+
*/
|
|
9
|
+
export function wordEndingAt(context, at, longest = 4) {
|
|
10
|
+
for (let length = longest; length > 0; length--) {
|
|
11
|
+
const from = at - length;
|
|
12
|
+
if (from < 0) {
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
const text = context.characters.slice(from, at).join("");
|
|
16
|
+
if (context.dictionary.lookup(text) !== undefined) {
|
|
17
|
+
return text;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The word starting at a position, longest first, or undefined.
|
|
24
|
+
*/
|
|
25
|
+
export function wordStartingAt(context, at, longest = 4) {
|
|
26
|
+
for (let length = longest; length > 0; length--) {
|
|
27
|
+
// Nothing starts at the end of a run, which is where a 得 closing a
|
|
28
|
+
// sentence asks from.
|
|
29
|
+
const text = context.characters.slice(at, at + length).join("");
|
|
30
|
+
if (text !== "" && context.dictionary.lookup(text) !== undefined) {
|
|
31
|
+
return text;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The part of speech the dictionary gives a word, or the empty string.
|
|
38
|
+
*/
|
|
39
|
+
export function tagOf(context, word) {
|
|
40
|
+
return word === undefined
|
|
41
|
+
? ""
|
|
42
|
+
: (context.dictionary.lookup(word)?.partOfSpeech ?? "");
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Whether every position can still be left, and the end still reached.
|
|
46
|
+
*
|
|
47
|
+
* A rule that forbids an edge can strand a stretch of the run — that is the one
|
|
48
|
+
* way a rule can do real damage, since a lattice with no path through it has no
|
|
49
|
+
* decode at all. Checked rather than reasoned about, because the rules are meant
|
|
50
|
+
* to be extensible and somebody else's rule is not this file's to trust.
|
|
51
|
+
*/
|
|
52
|
+
function isTraversable(lattice) {
|
|
53
|
+
const length = lattice.characters.length;
|
|
54
|
+
const reaches = Array.from({ length: length + 1 }, () => false);
|
|
55
|
+
reaches[length] = true;
|
|
56
|
+
for (let at = length - 1; at >= 0; at--) {
|
|
57
|
+
/* c8 ignore next 3 -- every index here is a position of the run itself */
|
|
58
|
+
reaches[at] = (lattice.edges[at] ?? []).some((edge) => reaches[edge.to] ?? false);
|
|
59
|
+
}
|
|
60
|
+
/* c8 ignore next -- a run always has a position 0 */
|
|
61
|
+
return reaches[0] ?? false;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* The verdict the first rule with an opinion gives an edge.
|
|
65
|
+
*/
|
|
66
|
+
function verdictFor(rules, context) {
|
|
67
|
+
for (const rule of rules) {
|
|
68
|
+
const verdict = rule.verdictFor(context);
|
|
69
|
+
if (verdict !== "keep") {
|
|
70
|
+
return verdict;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return "keep";
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Forbid every edge a forced one covers the same characters as.
|
|
77
|
+
*
|
|
78
|
+
* All the edges leaving a position are given together, so covering the same
|
|
79
|
+
* characters is a question about where they end. A forced edge never forbids
|
|
80
|
+
* another forced one: two rules forcing the same span disagree, and the decode
|
|
81
|
+
* choosing between the two readings is a better answer than neither.
|
|
82
|
+
*/
|
|
83
|
+
function forbidRivals(edges, forced, forbidden) {
|
|
84
|
+
const settled = new Set(edges.filter((edge) => forced.has(edge)).map((edge) => edge.to));
|
|
85
|
+
for (const rival of edges) {
|
|
86
|
+
if (settled.has(rival.to) && !forced.has(rival)) {
|
|
87
|
+
forbidden.add(rival);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Apply the rules to a lattice, returning the lattice they leave.
|
|
93
|
+
*
|
|
94
|
+
* Stage 4 of the pipeline: the rules run over the built lattice and before any
|
|
95
|
+
* decoding, so what they change is what the decode gets to choose between
|
|
96
|
+
* rather than what it has already chosen. Nothing is rewritten — an edge is
|
|
97
|
+
* kept or it is not — which is what keeps a rule from inventing a reading no
|
|
98
|
+
* source attests.
|
|
99
|
+
*
|
|
100
|
+
* The lattice is returned unchanged if the rules would leave the run with no
|
|
101
|
+
* path through it.
|
|
102
|
+
*/
|
|
103
|
+
export function applyEdgeRules(lattice, dictionary, rules) {
|
|
104
|
+
if (rules.length === 0) {
|
|
105
|
+
return lattice;
|
|
106
|
+
}
|
|
107
|
+
const forbidden = new Set();
|
|
108
|
+
const forced = new Set();
|
|
109
|
+
for (const edges of lattice.edges) {
|
|
110
|
+
for (const edge of edges) {
|
|
111
|
+
const verdict = verdictFor(rules, {
|
|
112
|
+
dictionary,
|
|
113
|
+
characters: lattice.characters,
|
|
114
|
+
edge,
|
|
115
|
+
});
|
|
116
|
+
if (verdict === "forbid") {
|
|
117
|
+
forbidden.add(edge);
|
|
118
|
+
}
|
|
119
|
+
else if (verdict === "force") {
|
|
120
|
+
forced.add(edge);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// Rivals are forbidden after every verdict is in, so that two rules forcing
|
|
125
|
+
// the same span leave both readings standing rather than neither.
|
|
126
|
+
for (const edges of lattice.edges) {
|
|
127
|
+
forbidRivals(edges, forced, forbidden);
|
|
128
|
+
}
|
|
129
|
+
if (forbidden.size === 0) {
|
|
130
|
+
return lattice;
|
|
131
|
+
}
|
|
132
|
+
const ruled = {
|
|
133
|
+
characters: lattice.characters,
|
|
134
|
+
edges: lattice.edges.map((edges) => edges.filter((edge) => !forbidden.has(edge))),
|
|
135
|
+
};
|
|
136
|
+
return isTraversable(ruled) ? ruled : lattice;
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules.js","sourceRoot":"","sources":["../../src/decode/rules.ts"],"names":[],"mappings":"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"}
|
package/dist/decode/sandhi.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sandhi.d.ts","sourceRoot":"","sources":["../../src/decode/sandhi.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"sandhi.d.ts","sourceRoot":"","sources":["../../src/decode/sandhi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAyB,MAAM,yBAAyB,CAAC;AAG/E;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB;;;;;;OAMG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CAC9B;AAwFD;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CACzB,SAAS,EAAE,SAAS,QAAQ,EAAE,EAC9B,OAAO,GAAE,aAAkB,GAC1B,SAAS,QAAQ,EAAE,CAiCrB"}
|
package/dist/decode/sandhi.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { writeSyllableSpelling } from "../syllable/syllable.js";
|
|
1
2
|
import { NEUTRAL_TONE } from "../tone/tone.js";
|
|
2
3
|
/**
|
|
3
4
|
* Whether a syllable is 一, which is the only thing spelled `yi` that sandhis.
|
|
@@ -24,6 +25,60 @@ function yiToneBefore(following) {
|
|
|
24
25
|
}
|
|
25
26
|
return following === 4 ? 2 : 4;
|
|
26
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* The numeral words a 一 can be the last digit of.
|
|
30
|
+
*
|
|
31
|
+
* Toneless, because what is being asked is which word it is rather than what
|
|
32
|
+
* tone it is carrying, and 十 is `shí` in every context it appears in here.
|
|
33
|
+
*
|
|
34
|
+
* **亿 is deliberately absent**, and that is measured rather than assumed: no
|
|
35
|
+
* 一 in 88,866 lines of Tatoeba and zh.wikipedia ends a number in 亿, while 意,
|
|
36
|
+
* 议, 义 and 議 all read `yì`, all precede a 一 that really is counting, and
|
|
37
|
+
* would all lose their sandhi for it — 11 conversions against nothing gained.
|
|
38
|
+
* The other three stay, because a number can end 百一 or 千一 even though this
|
|
39
|
+
* corpus has none, and the one thing they cost is 擺一個.
|
|
40
|
+
*/
|
|
41
|
+
const NUMERAL_WORDS = new Set(["shi", "bai", "qian", "wan"]);
|
|
42
|
+
/**
|
|
43
|
+
* The words that carry a number on past a 一, so that it is still counting.
|
|
44
|
+
*
|
|
45
|
+
* 一百一十's second 一 counts the ten it is followed by and takes the sandhi;
|
|
46
|
+
* 二十一's does not, because nothing numeric comes after it.
|
|
47
|
+
*/
|
|
48
|
+
const CONTINUES_NUMBER = new Set([...NUMERAL_WORDS, "ling"]);
|
|
49
|
+
/**
|
|
50
|
+
* The ordinal prefix 第.
|
|
51
|
+
*/
|
|
52
|
+
const ORDINAL_PREFIX = "di";
|
|
53
|
+
/**
|
|
54
|
+
* Whether a 一 is counting something, which is the only time it takes sandhi.
|
|
55
|
+
*
|
|
56
|
+
* The rule 一 sandhi is usually stated with — fourth tone flattens it, anything
|
|
57
|
+
* else raises it — is about the 一 that *counts*. Two shapes of 一 are not
|
|
58
|
+
* counting and keep the citation tone, and both are standard:
|
|
59
|
+
*
|
|
60
|
+
* - **The last digit of a larger number.** 十一月 is `shíyīyuè` and 二十一岁 is
|
|
61
|
+
* `èrshíyī suì`. The signal is a numeral word before it with nothing numeric
|
|
62
|
+
* after, which is what leaves 一百一十's middle 一 alone: 十 follows it, so it
|
|
63
|
+
* is counting the ten.
|
|
64
|
+
* - **An ordinal.** 第一个 is `dìyī gè`.
|
|
65
|
+
*
|
|
66
|
+
* **Read off the syllables rather than the characters**, because that is all
|
|
67
|
+
* this pass has: `pinyinjs sandhi shíyī gè` never sees a hanzi. So it cannot
|
|
68
|
+
* tell 十 from 时 or 第 from 地, and `docs/sandhi/` carries what that costs —
|
|
69
|
+
* measured, not estimated.
|
|
70
|
+
*/
|
|
71
|
+
function isCounting(syllables, at) {
|
|
72
|
+
const spelt = (index) => {
|
|
73
|
+
const syllable = syllables[index];
|
|
74
|
+
return syllable === undefined ? "" : writeSyllableSpelling(syllable);
|
|
75
|
+
};
|
|
76
|
+
const before = spelt(at - 1);
|
|
77
|
+
if (before === ORDINAL_PREFIX) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
return !NUMERAL_WORDS.has(before) || CONTINUES_NUMBER.has(spelt(at + 1));
|
|
81
|
+
}
|
|
27
82
|
/**
|
|
28
83
|
* Apply the tone sandhi that standard orthography writes.
|
|
29
84
|
*
|
|
@@ -42,7 +97,11 @@ export function applySandhi(syllables, options = {}) {
|
|
|
42
97
|
for (const [at, syllable] of applied.entries()) {
|
|
43
98
|
const following = applied[at + 1];
|
|
44
99
|
if (yiBu && isYi(syllable) && syllable.tone === 1) {
|
|
45
|
-
|
|
100
|
+
// A 一 that is not counting keeps its citation tone, so it is left
|
|
101
|
+
// exactly as the dictionary stored it.
|
|
102
|
+
if (isCounting(applied, at)) {
|
|
103
|
+
applied[at] = { ...syllable, tone: yiToneBefore(following?.tone) };
|
|
104
|
+
}
|
|
46
105
|
continue;
|
|
47
106
|
}
|
|
48
107
|
// 不 flattens to second tone before a fourth, and is otherwise unchanged.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sandhi.js","sourceRoot":"","sources":["../../src/decode/sandhi.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sandhi.js","sourceRoot":"","sources":["../../src/decode/sandhi.ts"],"names":[],"mappings":"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"}
|
package/dist/decode/word.d.ts
CHANGED
|
@@ -13,7 +13,25 @@ export interface DecodedWord {
|
|
|
13
13
|
readonly partOfSpeech: string;
|
|
14
14
|
/** Whether a dictionary entry was found, rather than a character fallback. */
|
|
15
15
|
readonly isKnown: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* What is written in front of this word, where it is not a space.
|
|
18
|
+
*
|
|
19
|
+
* Only 分词连写 sets it, and only to a hyphen: the two halves of 干干净净
|
|
20
|
+
* are written `gāngān-jìngjìng`, one orthographic word with a boundary
|
|
21
|
+
* inside it rather than two words. Keeping them two decoded words and
|
|
22
|
+
* recording the mark between them is what lets the halves carry their own
|
|
23
|
+
* readings and capitals — see {@link WordSeparator}.
|
|
24
|
+
*/
|
|
25
|
+
readonly separator?: WordSeparator;
|
|
16
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* A mark GB/T 16159 writes between two words instead of a space.
|
|
29
|
+
*
|
|
30
|
+
* A hyphen is the only one, and it does not mean the same thing as a space: a
|
|
31
|
+
* hyphenated pair is read back as a single word, which is why
|
|
32
|
+
* `splitSyllables` treats it as a syllable boundary rather than a word one.
|
|
33
|
+
*/
|
|
34
|
+
export type WordSeparator = "-";
|
|
17
35
|
/**
|
|
18
36
|
* A decoded word together with how settled each of its syllables was.
|
|
19
37
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"word.d.ts","sourceRoot":"","sources":["../../src/decode/word.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,gDAAgD;IAChD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,SAAS,QAAQ,EAAE,CAAC;IACtC,qDAAqD;IACrD,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,qDAAqD;IACrD,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,8EAA8E;IAC9E,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"word.d.ts","sourceRoot":"","sources":["../../src/decode/word.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,gDAAgD;IAChD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,SAAS,QAAQ,EAAE,CAAC;IACtC,qDAAqD;IACrD,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,qDAAqD;IACrD,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,8EAA8E;IAC9E,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B;;;;;;;;OAQG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,CAAC;CACpC;AAED;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GAAG,GAAG,CAAC;AAEhC;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B;;;;;;OAMG;IACH,QAAQ,CAAC,UAAU,EAAE,SAAS,iBAAiB,EAAE,CAAC;CACnD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"artifact.d.ts","sourceRoot":"","sources":["../../src/dictionary/artifact.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,QAAQ,EAEd,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"artifact.d.ts","sourceRoot":"","sources":["../../src/dictionary/artifact.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,QAAQ,EAEd,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAkDlD;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IACjC,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,sCAAsC;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,kDAAkD;IAClD,QAAQ,CAAC,WAAW,EAAE,UAAU,CAAC;CAClC;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,SAAS,QAAQ,EAAE,GAAG,MAAM,CAIpE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,QAAQ,EAAE,GAAG,SAAS,CAQ3E;AAYD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,GAAG,SAAS,MAAM,EAAE,CAE1E;AA+GD;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,SAAS,eAAe,EAAE,GAClC,kBAAkB,CAqCpB;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,kBAAkB,GAC3B,SAAS,eAAe,EAAE,CA2D5B;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,SAAS,eAAe,EAAE,EACnC,QAAQ,EAAE,kBAAkB,GAC3B,MAAM,GAAG,SAAS,CAkBpB"}
|
|
@@ -19,6 +19,28 @@ const ALTERNATE = ",";
|
|
|
19
19
|
* The flag marking a proper noun.
|
|
20
20
|
*/
|
|
21
21
|
const PROPER_NOUN_FLAG = "p";
|
|
22
|
+
/**
|
|
23
|
+
* Where a proper name divides, written after the proper-noun flag.
|
|
24
|
+
*
|
|
25
|
+
* `p` alone is a proper noun whose parts CC-CEDICT does not divide; `p1` is one
|
|
26
|
+
* that divides after the first character, `p2.4` after the second and fourth.
|
|
27
|
+
* The positions are decimal and dot-separated rather than one digit each,
|
|
28
|
+
* because the longest word carrying any is 19 characters.
|
|
29
|
+
*
|
|
30
|
+
* It rides in the flags column rather than taking a column of its own because
|
|
31
|
+
* it is only ever present on a proper noun, and only 8,205 of 723,139 keys
|
|
32
|
+
* carry one — a sixth column would cost a separator on every line to say
|
|
33
|
+
* nothing on almost all of them.
|
|
34
|
+
*/
|
|
35
|
+
const NAME_BOUNDARIES = /^p(?<at>\d+(?:\.\d+)*)$/u;
|
|
36
|
+
const BOUNDARY_SEPARATOR = ".";
|
|
37
|
+
/**
|
|
38
|
+
* The boundaries a flags column states, empty where it states none.
|
|
39
|
+
*/
|
|
40
|
+
function nameBoundariesIn(flags) {
|
|
41
|
+
const at = NAME_BOUNDARIES.exec(flags)?.groups?.["at"];
|
|
42
|
+
return at === undefined ? [] : at.split(BOUNDARY_SEPARATOR).map(Number);
|
|
43
|
+
}
|
|
22
44
|
/**
|
|
23
45
|
* Write a reading in tone-numbered notation.
|
|
24
46
|
*
|
|
@@ -176,7 +198,10 @@ export function buildArtifact(entries) {
|
|
|
176
198
|
isDerivable(key, reading, defaults) ? "" : reading,
|
|
177
199
|
entry.readings.tw === undefined ? "" : encodeReading(entry.readings.tw),
|
|
178
200
|
entry.partOfSpeech,
|
|
179
|
-
entry.isProperNoun
|
|
201
|
+
entry.isProperNoun
|
|
202
|
+
? PROPER_NOUN_FLAG +
|
|
203
|
+
(entry.nameBoundaries ?? []).join(BOUNDARY_SEPARATOR)
|
|
204
|
+
: "",
|
|
180
205
|
(entry.alternates ?? [])
|
|
181
206
|
.map((alternate) => encodeReading(alternate))
|
|
182
207
|
.join(ALTERNATE),
|
|
@@ -215,6 +240,7 @@ export function readArtifact(artifact) {
|
|
|
215
240
|
for (let at = 0; at < index.size; at++) {
|
|
216
241
|
const key = index.keyAt(at);
|
|
217
242
|
const [reading = "", taiwan = "", partOfSpeech = "", flags = "", alternates = "",] = (lines[at] ?? "").split(COLUMN);
|
|
243
|
+
const nameBoundaries = nameBoundariesIn(flags);
|
|
218
244
|
const stored = reading === ""
|
|
219
245
|
? toCharacters(key)
|
|
220
246
|
.map((character) => defaults.get(character) ?? "")
|
|
@@ -234,6 +260,7 @@ export function readArtifact(artifact) {
|
|
|
234
260
|
frequency: frequencies.bucketOf(at),
|
|
235
261
|
partOfSpeech,
|
|
236
262
|
isProperNoun: flags.includes(PROPER_NOUN_FLAG),
|
|
263
|
+
...(nameBoundaries.length > 0 && { nameBoundaries }),
|
|
237
264
|
...(alternates !== "" && {
|
|
238
265
|
alternates: alternates
|
|
239
266
|
.split(ALTERNATE)
|