Skip to content

Commit 118552d

Browse files
authored
fix: センテンス内の「」や""などにおける区切り文字を考慮するように修正 (#47)
* fix: センテンス内の「」や""などにおける区切り文字を考慮するように修正 センテンスの中に「xxx. yyy.」があると、センテンスの中にさらに区切り文字(。.など)が含まれているケースがある。 この場合も、区切り文字を+1の距離として扱うことで、「」の中にサブセンテンスを書いているケースをエラーにしないようにした * test: add test case * fix
1 parent 20a619b commit 118552d

File tree

3 files changed

+53
-7
lines changed

3 files changed

+53
-7
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ textlint --rule no-doubled-joshi README.md
9696
- `strict`: 厳しくチェックするかどうか
9797
- Default: `false`
9898
- 下記参照。例外としているものもエラーとするかどうか
99-
- false-positiveが発生しやすくなります
99+
- `true`にすると誤検知が発生しやすくなります
100100
- `allow`: 複数回の出現を許す助詞
101101
- Default: `[]`
102102
- 並立の助詞など、複数回出現しても無視する助詞を指定します

src/no-doubled-joshi.ts

+38-5
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
restoreToSurfaceFromKey,
1212
is括弧Token,
1313
} from "./token-utils";
14-
import { TxtNode } from "@textlint/ast-node-types";
14+
import { TxtNode, TxtParentNode } from "@textlint/ast-node-types";
1515
import { TextlintRuleModule } from "@textlint/types";
1616
import { StringSource } from "textlint-util-to-string";
1717

@@ -84,6 +84,7 @@ export interface Options {
8484
/**
8585
* 助詞の最低間隔値
8686
* 指定した間隔値以下で同じ助詞が出現した場合エラーが出力されます
87+
* デフォルトは1なので、同じ助詞が連続した場合にエラーとなります。
8788
*/
8889
min_interval?: number;
8990
/**
@@ -106,13 +107,36 @@ export interface Options {
106107
commaCharacters?: string[];
107108
}
108109

110+
/**
111+
* `obj.method` のCode Nodeのように、区切り文字として意味をもつノードがある場合に、
112+
* このルールでは単純に無視したいので、同じ文字数で意味のない文字列に置き換える
113+
* @param sentenceNode
114+
* @param maskedType
115+
*/
116+
const maskNode = (sentenceNode: TxtParentNode, maskedType: string[]): TxtParentNode => {
117+
// recursive mask
118+
return {
119+
...sentenceNode,
120+
children: sentenceNode.children.map((node) => {
121+
if (maskedType.includes(node.type)) {
122+
return {
123+
...node,
124+
type: node.type,
125+
value: "_".repeat(node.value.length),
126+
};
127+
}
128+
if (node.children) {
129+
return maskNode(node as TxtParentNode, maskedType);
130+
}
131+
return node;
132+
})
133+
}
134+
}
109135
/*
110136
1. Paragraph Node -> text
111137
2. text -> sentences
112138
3. tokenize sentence
113139
4. report error if found word that match the rule.
114-
115-
TODO: need abstraction
116140
*/
117141
const report: TextlintRuleModule<Options> = function (context, options = {}) {
118142
const helper = new RuleHelper(context);
@@ -142,7 +166,9 @@ const report: TextlintRuleModule<Options> = function (context, options = {}) {
142166
});
143167
const sentences = txtParentNode.children.filter(isSentenceNode);
144168
const checkSentence = async (sentence: SentenceNode) => {
145-
const sentenceSource = new StringSource(sentence);
169+
// コードの中身は無視するため、無意味な文字列に置き換える
170+
const maskedSentence = maskNode(sentence, [Syntax.Code]);
171+
const sentenceSource = new StringSource(maskedSentence);
146172
const text = sentenceSource.toString();
147173
const tokens = await tokenize(text);
148174
// 助詞 + 助詞は 一つの助詞として扱う
@@ -154,18 +180,25 @@ const report: TextlintRuleModule<Options> = function (context, options = {}) {
154180
if (isStrict) {
155181
return is助詞Token(token);
156182
}
183+
// デフォルトでは、"、"などを間隔値の距離としてカウントする
157184
// "("や")"などもトークンとしてカウントする
158185
// xxxx(xxx) xxx でカッコの中と外に距離を一つ増やす目的
159186
// https://github.com/textlint-ja/textlint-rule-no-doubled-joshi/issues/31
160187
if (is括弧Token(token)) {
161188
return true;
162189
}
190+
// sentence-splitterでセンテンスに区切った場合、 "Xは「カッコ書きの中の文」と言った。" というように、「」の中の文は区切られない
191+
// そのため、トークナイズしたトークンで区切り文字となる文字(。や.)があった場合には、カウントを増やす 
192+
// デフォルトではmin_interval:1 なので、「今日は早朝から出発したが、定刻には間に合わなかった。定刻には間に合わなかったが、無事会場に到着した」のようなものがエラーではなくなる
193+
// https://github.com/textlint-ja/textlint-rule-no-doubled-joshi/issues/40
194+
if (separatorCharacters.includes(token.surface_form)) {
195+
return true;
196+
}
163197
// "、" があると助詞同士の距離が開くようにすることで、並列的な"、"の使い方を許容する目的
164198
// https://github.com/azu/textlint-rule-no-doubled-joshi/issues/2
165199
if (is読点Token(token)) {
166200
return true;
167201
}
168-
// デフォルトでは、"、"を間隔値の距離としてカウントする
169202
return is助詞Token(token);
170203
});
171204
const joshiTokenSurfaceKeyMap = createSurfaceKeyMap(countableTokens);

test/no-doubled-joshi-test.ts

+14-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import rule from "../src/no-doubled-joshi";
44
const tester = new TextLintTester();
55
tester.run("no-double-joshi", rule, {
66
valid: [
7-
"私は彼が好きだ",
87
"既存のコードの利用", // "の" の例外
98
"オブジェクトを返す関数を公開した", // "を" の例外
109
"私は彼の鼻は好きだ",
@@ -37,6 +36,11 @@ tester.run("no-double-joshi", rule, {
3736
" 次の`escapeHTML`関数は**タグ関数**です(詳細は文字列の章を参照)。",
3837
// 1個目の「と」は格助詞、2個めの「と」は接続助詞
3938
"ターミナルで「test」**と**入力する**と**、画面に表示されます。",
39+
// センテンスの中での。の句点を考慮する
40+
// https://github.com/textlint-ja/textlint-rule-no-doubled-joshi/issues/40
41+
"昨日は「今日は早朝から出発したが、定刻には間に合わなかった。定刻には間に合わなかったが、無事会場に到着した」と思った",
42+
"「今日は早朝から出発したが、定刻には間に合わなかった。定刻には間に合わなかったが、無事会場に到着した」",
43+
`"今日は早朝から出発したが、定刻には間に合わなかった。定刻には間に合わなかったが、無事会場に到着した"`,
4044
// 格助詞の種類が異なる
4145
// "プロパティを削除しようとするとエラーが発生します。",
4246
// 「でも」と「も」は並列としても扱うケースがある
@@ -74,6 +78,15 @@ tester.run("no-double-joshi", rule, {
7478
},
7579
],
7680
},
81+
{
82+
text: "あなたは「私は彼は好きだ」と言った。",
83+
errors: [
84+
{
85+
message: `一文に二回以上利用されている助詞 "は" がみつかりました。`,
86+
index: 8,
87+
},
88+
],
89+
},
7790
{
7891
text: "材料不足で代替素材で製品を作った。",
7992
errors: [

0 commit comments

Comments
 (0)