Skip to content

fix: センテンス内の「」や""などにおける区切り文字を考慮するように修正 #47

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ textlint --rule no-doubled-joshi README.md
- `strict`: 厳しくチェックするかどうか
- Default: `false`
- 下記参照。例外としているものもエラーとするかどうか
- false-positiveが発生しやすくなります
- `true`にすると誤検知が発生しやすくなります
- `allow`: 複数回の出現を許す助詞
- Default: `[]`
- 並立の助詞など、複数回出現しても無視する助詞を指定します
Expand Down
43 changes: 38 additions & 5 deletions src/no-doubled-joshi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
restoreToSurfaceFromKey,
is括弧Token,
} from "./token-utils";
import { TxtNode } from "@textlint/ast-node-types";
import { TxtNode, TxtParentNode } from "@textlint/ast-node-types";
import { TextlintRuleModule } from "@textlint/types";
import { StringSource } from "textlint-util-to-string";

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

/**
* `obj.method` のCode Nodeのように、区切り文字として意味をもつノードがある場合に、
* このルールでは単純に無視したいので、同じ文字数で意味のない文字列に置き換える
* @param sentenceNode
* @param maskedType
*/
const maskNode = (sentenceNode: TxtParentNode, maskedType: string[]): TxtParentNode => {
// recursive mask
return {
...sentenceNode,
children: sentenceNode.children.map((node) => {
if (maskedType.includes(node.type)) {
return {
...node,
type: node.type,
value: "_".repeat(node.value.length),
};
}
if (node.children) {
return maskNode(node as TxtParentNode, maskedType);
}
return node;
})
}
}
/*
1. Paragraph Node -> text
2. text -> sentences
3. tokenize sentence
4. report error if found word that match the rule.

TODO: need abstraction
*/
const report: TextlintRuleModule<Options> = function (context, options = {}) {
const helper = new RuleHelper(context);
Expand Down Expand Up @@ -142,7 +166,9 @@ const report: TextlintRuleModule<Options> = function (context, options = {}) {
});
const sentences = txtParentNode.children.filter(isSentenceNode);
const checkSentence = async (sentence: SentenceNode) => {
const sentenceSource = new StringSource(sentence);
// コードの中身は無視するため、無意味な文字列に置き換える
const maskedSentence = maskNode(sentence, [Syntax.Code]);
const sentenceSource = new StringSource(maskedSentence);
const text = sentenceSource.toString();
const tokens = await tokenize(text);
// 助詞 + 助詞は 一つの助詞として扱う
Expand All @@ -154,18 +180,25 @@ const report: TextlintRuleModule<Options> = function (context, options = {}) {
if (isStrict) {
return is助詞Token(token);
}
// デフォルトでは、"、"などを間隔値の距離としてカウントする
// "("や")"などもトークンとしてカウントする
// xxxx(xxx) xxx でカッコの中と外に距離を一つ増やす目的
// https://github.com/textlint-ja/textlint-rule-no-doubled-joshi/issues/31
if (is括弧Token(token)) {
return true;
}
// sentence-splitterでセンテンスに区切った場合、 "Xは「カッコ書きの中の文」と言った。" というように、「」の中の文は区切られない
// そのため、トークナイズしたトークンで区切り文字となる文字(。や.)があった場合には、カウントを増やす 
// デフォルトではmin_interval:1 なので、「今日は早朝から出発したが、定刻には間に合わなかった。定刻には間に合わなかったが、無事会場に到着した」のようなものがエラーではなくなる
// https://github.com/textlint-ja/textlint-rule-no-doubled-joshi/issues/40
if (separatorCharacters.includes(token.surface_form)) {
return true;
}
// "、" があると助詞同士の距離が開くようにすることで、並列的な"、"の使い方を許容する目的
// https://github.com/azu/textlint-rule-no-doubled-joshi/issues/2
if (is読点Token(token)) {
return true;
}
// デフォルトでは、"、"を間隔値の距離としてカウントする
return is助詞Token(token);
});
const joshiTokenSurfaceKeyMap = createSurfaceKeyMap(countableTokens);
Expand Down
15 changes: 14 additions & 1 deletion test/no-doubled-joshi-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import rule from "../src/no-doubled-joshi";
const tester = new TextLintTester();
tester.run("no-double-joshi", rule, {
valid: [
"私は彼が好きだ",
"既存のコードの利用", // "の" の例外
"オブジェクトを返す関数を公開した", // "を" の例外
"私は彼の鼻は好きだ",
Expand Down Expand Up @@ -37,6 +36,11 @@ tester.run("no-double-joshi", rule, {
" 次の`escapeHTML`関数は**タグ関数**です(詳細は文字列の章を参照)。",
// 1個目の「と」は格助詞、2個めの「と」は接続助詞
"ターミナルで「test」**と**入力する**と**、画面に表示されます。",
// センテンスの中での。の句点を考慮する
// https://github.com/textlint-ja/textlint-rule-no-doubled-joshi/issues/40
"昨日は「今日は早朝から出発したが、定刻には間に合わなかった。定刻には間に合わなかったが、無事会場に到着した」と思った",
"「今日は早朝から出発したが、定刻には間に合わなかった。定刻には間に合わなかったが、無事会場に到着した」",
`"今日は早朝から出発したが、定刻には間に合わなかった。定刻には間に合わなかったが、無事会場に到着した"`,
// 格助詞の種類が異なる
// "プロパティを削除しようとするとエラーが発生します。",
// 「でも」と「も」は並列としても扱うケースがある
Expand Down Expand Up @@ -74,6 +78,15 @@ tester.run("no-double-joshi", rule, {
},
],
},
{
text: "あなたは「私は彼は好きだ」と言った。",
errors: [
{
message: `一文に二回以上利用されている助詞 "は" がみつかりました。`,
index: 8,
},
],
},
{
text: "材料不足で代替素材で製品を作った。",
errors: [
Expand Down