chaffjs 0.12.0 → 0.13.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/dist/detectors/acronym-context.d.ts +15 -3
- package/dist/detectors/acronym-context.d.ts.map +1 -1
- package/dist/detectors/acronym-context.js +18 -32
- package/dist/detectors/acronym-context.js.map +1 -1
- package/dist/detectors/acronym-expansion.d.ts.map +1 -1
- package/dist/detectors/acronym-expansion.js +33 -6
- package/dist/detectors/acronym-expansion.js.map +1 -1
- package/dist/detectors/char-shape.d.ts.map +1 -1
- package/dist/detectors/char-shape.js +20 -34
- package/dist/detectors/char-shape.js.map +1 -1
- package/dist/detectors/orthography.d.ts.map +1 -1
- package/dist/detectors/orthography.js +17 -1
- package/dist/detectors/orthography.js.map +1 -1
- package/dist/detectors/place-run.d.ts +8 -0
- package/dist/detectors/place-run.d.ts.map +1 -0
- package/dist/detectors/place-run.js +54 -0
- package/dist/detectors/place-run.js.map +1 -0
- package/dist/detectors/register.d.ts +32 -0
- package/dist/detectors/register.d.ts.map +1 -0
- package/dist/detectors/register.js +62 -0
- package/dist/detectors/register.js.map +1 -0
- package/dist/detectors/sentence-ending.d.ts.map +1 -1
- package/dist/detectors/sentence-ending.js +17 -28
- package/dist/detectors/sentence-ending.js.map +1 -1
- package/dist/detectors/signals.d.ts.map +1 -1
- package/dist/detectors/signals.js +13 -6
- package/dist/detectors/signals.js.map +1 -1
- package/dist/number-name.d.ts +9 -0
- package/dist/number-name.d.ts.map +1 -0
- package/dist/number-name.js +57 -0
- package/dist/number-name.js.map +1 -0
- package/dist/orthography.d.ts +6 -2
- package/dist/orthography.d.ts.map +1 -1
- package/dist/orthography.js +78 -17
- package/dist/orthography.js.map +1 -1
- package/package.json +3 -3
- package/rules/latin-spacing.yaml +4 -2
- package/rules/max-kanji-continuous.yaml +2 -0
- package/rules/undefined-acronym.yaml +1 -0
- package/src/detectors/acronym-context.ts +30 -33
- package/src/detectors/acronym-expansion.ts +34 -6
- package/src/detectors/char-shape.ts +12 -30
- package/src/detectors/orthography.ts +20 -2
- package/src/detectors/place-run.ts +63 -0
- package/src/detectors/register.ts +83 -0
- package/src/detectors/sentence-ending.ts +24 -28
- package/src/detectors/signals.ts +15 -6
- package/src/number-name.ts +68 -0
- package/src/orthography.ts +76 -15
package/src/orthography.ts
CHANGED
|
@@ -62,23 +62,53 @@ const latinBeside = (japanese: string | undefined, other: string | undefined, di
|
|
|
62
62
|
isJapanese(japanese) ? kindOf(other, digitSide) : undefined;
|
|
63
63
|
|
|
64
64
|
/** 日本語の字の隣にある英字・数字との境目。間が半角空白 1 つなら「空けている」、何も無ければ「詰めている」。 */
|
|
65
|
-
|
|
65
|
+
// 「confidence=0」のような設定の書き方も、= を含めて一つの並びとして読む。
|
|
66
|
+
const ALPHANUMERIC = /[A-Za-z0-9.=]/u;
|
|
67
|
+
// 名前の語は英数字だけ。「API = 0」の空白で囲んだ = は式の記号で、名前の一部ではない。
|
|
68
|
+
const WORD_CHAR = /[A-Za-z0-9.]/u;
|
|
69
|
+
|
|
70
|
+
/** chars[last] を末尾とし、pattern の字が続く並びの、先頭の位置。 */
|
|
71
|
+
const runStartIndex = (chars: readonly string[], last: number, pattern: RegExp = ALPHANUMERIC): number => {
|
|
72
|
+
let first = last;
|
|
73
|
+
while (first > 0 && pattern.test(chars[first - 1] ?? "")) first -= 1;
|
|
74
|
+
return first;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
/** 並び first の前に、半角空白 1 つずつで続く英数字の語。「Phase 1」の「Phase」、「JIS X 0301」の「JIS X」。無ければ空。 */
|
|
78
|
+
const wordsBefore = (chars: readonly string[], first: number): string => {
|
|
79
|
+
const words: string[] = [];
|
|
80
|
+
let space = first - 1;
|
|
81
|
+
while (chars[space] === " " && WORD_CHAR.test(chars[space - 1] ?? "")) {
|
|
82
|
+
const start = runStartIndex(chars, space - 1, WORD_CHAR);
|
|
83
|
+
words.unshift(chars.slice(start, space).join(""));
|
|
84
|
+
space = start - 1;
|
|
85
|
+
}
|
|
86
|
+
return words.join(" ");
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// 「1ファイル x 1シート」の x のように、1 字だけの英字は記号か変数で、名前の頭ではない。
|
|
90
|
+
const MIN_NAME_LETTERS = 2;
|
|
66
91
|
|
|
67
92
|
/**
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* 逆に「H30 等」「EC2 で」は英字で始まる名前で、書き手は英単語と同じに空ける。数字の後ろとしては数えない。
|
|
93
|
+
* 「Phase 1 は」「iOS 17以上」の数字は、英字の語に続く名前の一部。空白は名前の中の空白で、日本語との境目は
|
|
94
|
+
* 「H30 等」と同じく英字の空け方として数える。
|
|
71
95
|
*/
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
return chars[first];
|
|
96
|
+
const isNameTail = (chars: readonly string[], first: number): boolean => {
|
|
97
|
+
const words = wordsBefore(chars, first);
|
|
98
|
+
return LETTER.test(words[0] ?? "") && (words.match(/[A-Za-z]/gu)?.length ?? 0) >= MIN_NAME_LETTERS;
|
|
76
99
|
};
|
|
77
100
|
|
|
78
|
-
/**
|
|
101
|
+
/**
|
|
102
|
+
* 日本語の左にある英数字の並びの種類は、先頭の字で決める。「3GBの」の「GB」は数量の単位で、並びは数字で始まる。
|
|
103
|
+
* そうした並びと日本語の境目は、英字の空け方ではなく数字の後ろの空け方として数える(「3回」と同じ)。
|
|
104
|
+
* 逆に「H30 等」「EC2 で」「v1.2の」は英字で始まる名前で、書き手は英単語と同じに空ける。
|
|
105
|
+
*/
|
|
79
106
|
const leftRunBeside = (chars: readonly string[], last: number, japanese: string | undefined): SpacingKind | undefined => {
|
|
80
107
|
const kind = latinBeside(japanese, chars[last], "after-digit");
|
|
81
|
-
|
|
108
|
+
if (kind === undefined) return undefined;
|
|
109
|
+
const first = runStartIndex(chars, last);
|
|
110
|
+
if (DIGIT.test(chars[first] ?? "") && isNameTail(chars, first)) return "letter";
|
|
111
|
+
return kindOf(chars[first], "after-digit") ?? kind;
|
|
82
112
|
};
|
|
83
113
|
|
|
84
114
|
/**
|
|
@@ -94,10 +124,37 @@ const isOrdinalRun = (chars: readonly string[], index: number): boolean => {
|
|
|
94
124
|
return chars[before] === ORDINAL_PREFIX;
|
|
95
125
|
};
|
|
96
126
|
|
|
127
|
+
/**
|
|
128
|
+
* 「073-489-5909」「2026-06-02」「Ⅰ-4-1-3」のように - でつないだ 3 組以上の数字は、電話番号・日付・図の番号で
|
|
129
|
+
* 数量ではない。後ろの空白は欄の区切りで、「3回」の空け方とは別のもの。両側とも数えない。
|
|
130
|
+
* 2 組(「1-3ヶ月」「20-30分」)は幅のある数量なので数える。
|
|
131
|
+
*/
|
|
132
|
+
const MIN_CODE_GROUPS = 3;
|
|
133
|
+
const CODE_CHAR = /[\d-]/u;
|
|
134
|
+
|
|
135
|
+
const isCode = (chars: readonly string[], digit: number): boolean => {
|
|
136
|
+
let [first, last] = [digit, digit];
|
|
137
|
+
while (first > 0 && CODE_CHAR.test(chars[first - 1] ?? "")) first -= 1;
|
|
138
|
+
while (last < chars.length - 1 && CODE_CHAR.test(chars[last + 1] ?? "")) last += 1;
|
|
139
|
+
const groups = chars
|
|
140
|
+
.slice(first, last + 1)
|
|
141
|
+
.join("")
|
|
142
|
+
.split("-");
|
|
143
|
+
return groups.filter((group) => group !== "").length >= MIN_CODE_GROUPS;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
/** 日本語との境目にある数字が、数えない書き方(「第3条」の番地、「073-489-5909」の符号)か。 */
|
|
147
|
+
const isUncountedNumber = (chars: readonly string[], index: number): boolean => {
|
|
148
|
+
const [left, right] = [chars[index], chars[index + 1]];
|
|
149
|
+
if (DIGIT.test(left ?? "")) return isOrdinalRun(chars, index) || isCode(chars, index);
|
|
150
|
+
const next = right === " " ? index + 2 : index + 1;
|
|
151
|
+
if (!DIGIT.test(chars[next] ?? "")) return false;
|
|
152
|
+
return left === ORDINAL_PREFIX || (isJapanese(left) && isCode(chars, next));
|
|
153
|
+
};
|
|
154
|
+
|
|
97
155
|
const boundaryAt = (chars: readonly string[], index: number): Omit<Boundary, "offset"> | undefined => {
|
|
156
|
+
if (isUncountedNumber(chars, index)) return undefined;
|
|
98
157
|
const [left, right, after] = [chars[index], chars[index + 1], chars[index + 2]];
|
|
99
|
-
const numberAfterPrefix = left === ORDINAL_PREFIX && DIGIT.test((right === " " ? after : right) ?? "");
|
|
100
|
-
if (numberAfterPrefix || (DIGIT.test(left ?? "") && isOrdinalRun(chars, index))) return undefined;
|
|
101
158
|
const touching = latinBeside(left, right, "before-digit") ?? leftRunBeside(chars, index, right);
|
|
102
159
|
if (touching !== undefined) return { kind: touching, spaced: false };
|
|
103
160
|
if (right !== " ") return undefined;
|
|
@@ -105,15 +162,19 @@ const boundaryAt = (chars: readonly string[], index: number): Omit<Boundary, "of
|
|
|
105
162
|
return spaced === undefined ? undefined : { kind: spaced, spaced: true };
|
|
106
163
|
};
|
|
107
164
|
|
|
108
|
-
/**
|
|
109
|
-
|
|
165
|
+
/**
|
|
166
|
+
* 文の中の境目を全部。offset は境目の位置(左の字の直後、UTF-16)。配列を作り直さずに一度なめる。
|
|
167
|
+
* text は本文でないものを空白で覆った文、written は覆う前の同じ範囲。覆ってできた空白(リンクの「[」など)は
|
|
168
|
+
* 書き手が空けたものではないので、「空けている」とは数えない。
|
|
169
|
+
*/
|
|
170
|
+
export const latinBoundaries = (text: string, written: string = text): Boundary[] => {
|
|
110
171
|
const chars = [...text];
|
|
111
172
|
const found: Boundary[] = [];
|
|
112
173
|
let offset = 0;
|
|
113
174
|
chars.forEach((char, index) => {
|
|
114
175
|
offset += char.length;
|
|
115
176
|
const boundary = boundaryAt(chars, index);
|
|
116
|
-
if (boundary !== undefined) found.push({ ...boundary, offset });
|
|
177
|
+
if (boundary !== undefined && (!boundary.spaced || written[offset] === " ")) found.push({ ...boundary, offset });
|
|
117
178
|
});
|
|
118
179
|
return found;
|
|
119
180
|
};
|