Skip to content

Commit f27f7da

Browse files
committed
Merge pull request #7 from azu/different-joshi
feat(rule): 異なる種類の助詞の重複を許可する
2 parents be216db + fe89ac6 commit f27f7da

File tree

3 files changed

+65
-25
lines changed

3 files changed

+65
-25
lines changed

src/no-doubled-joshi.js

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,10 @@ import {RuleHelper} from "textlint-rule-helper";
44
import {getTokenizer} from "kuromojin";
55
import splitSentences, {Syntax as SentenceSyntax} from "sentence-splitter";
66
import StringSource from "textlint-util-to-string";
7-
// 助詞どうか
8-
const is助詞Token = token => {
9-
return token.pos === "助詞";
10-
};
11-
const is読点Token = token => {
12-
return token.surface_form === "、" && token.pos === "名詞";
13-
};
7+
import {
8+
is助詞Token, is読点Token,
9+
createKeyFromKey, restoreToSurfaceFromKey
10+
} from "./token-utils";
1411
/**
1512
* Create token map object
1613
* {
@@ -23,11 +20,12 @@ const is読点Token = token => {
2320
function createSurfaceKeyMap(tokens) {
2421
// 助詞のみを対象とする
2522
return tokens.filter(is助詞Token).reduce((keyMap, token) => {
26-
// "は" : [token]
27-
if (!keyMap[token.surface_form]) {
28-
keyMap[token.surface_form] = [];
23+
// "は:助詞.係助詞" : [token]
24+
const tokenKey = createKeyFromKey(token);
25+
if (!keyMap[tokenKey]) {
26+
keyMap[tokenKey] = [];
2927
}
30-
keyMap[token.surface_form].push(token);
28+
keyMap[tokenKey].push(token);
3129
return keyMap;
3230
}, {});
3331
}
@@ -100,12 +98,13 @@ export default function (context, options = {}) {
10098
10199
joshiTokens = [tokenA, tokenB, tokenC, tokenD, tokenE, tokenF]
102100
joshiTokenSurfaceKeyMap = {
103-
"は": [tokenA, tokenC, tokenE],
104-
"で": [tokenB, tokenD, tokenF]
101+
"は:助詞.係助詞": [tokenA, tokenC, tokenE],
102+
"で:助詞.係助詞": [tokenB, tokenD, tokenF]
105103
}
106104
*/
107105
Object.keys(joshiTokenSurfaceKeyMap).forEach(key => {
108-
let tokens = joshiTokenSurfaceKeyMap[key];
106+
const tokens = joshiTokenSurfaceKeyMap[key];
107+
const joshiName = restoreToSurfaceFromKey(key);
109108
// strict mode ではない時例外を除去する
110109
if (!isStrict) {
111110
if (matchExceptionRule(tokens)) {
@@ -117,27 +116,28 @@ export default function (context, options = {}) {
117116
}
118117
// if found differenceIndex less than
119118
// tokes are sorted ascending order
120-
tokens.reduce((prev, current) => {
121-
let startPosition = countableTokens.indexOf(prev);
122-
let otherPosition = countableTokens.indexOf(current);
123-
// if difference
124-
let differenceIndex = otherPosition - startPosition;
119+
var reduder = (prev, current) => {
120+
const startPosition = countableTokens.indexOf(prev);
121+
const otherPosition = countableTokens.indexOf(current);
122+
// 助詞token同士の距離が設定値以下ならエラーを報告する
123+
const differenceIndex = otherPosition - startPosition;
125124
if (differenceIndex <= minInterval) {
126-
let originalPosition = source.originalPositionFor({
125+
const originalPosition = source.originalPositionFor({
127126
line: sentence.loc.start.line,
128127
column: sentence.loc.start.column + (current.word_position - 1)
129128
});
130-
// padding position
131-
var padding = {
129+
// padding positionを計算する
130+
const padding = {
132131
line: originalPosition.line - 1,
133132
// matchLastToken.word_position start with 1
134133
// this is padding column start with 0 (== -1)
135134
column: originalPosition.column
136135
};
137-
report(node, new RuleError(`一文に二回以上利用されている助詞 "${key}" がみつかりました。`, padding));
136+
report(node, new RuleError(`一文に二回以上利用されている助詞 "${joshiName}" がみつかりました。`, padding));
138137
}
139138
return current;
140-
});
139+
};
140+
tokens.reduce(reduder);
141141
});
142142
};
143143
sentences.forEach(checkSentence);

src/token-utils.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// LICENSE : MIT
2+
"use strict";
3+
// 助詞どうか
4+
export const is助詞Token = (token) => {
5+
return token.pos === "助詞";
6+
};
7+
8+
export const is読点Token = (token) => {
9+
return token.surface_form === "、" && token.pos === "名詞";
10+
};
11+
12+
// 助詞tokenから品詞細分類1までを元にしたkeyを作る
13+
// http://www.unixuser.org/~euske/doc/postag/index.html#chasen
14+
// http://chasen.naist.jp/snapshot/ipadic/ipadic/doc/ipadic-ja.pdf
15+
export const createKeyFromKey = (token) => {
16+
// e.g.) "は:助詞.係助詞"
17+
return `${token.surface_form}:${token.pos}.${token.pos_detail_1}`
18+
};
19+
// keyからsurfaceを取り出す
20+
export const restoreToSurfaceFromKey = (key) => {
21+
return key.split(":")[0];
22+
};

test/no-doubled-joshi-test.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@ import assert from "power-assert";
22
import rule from "../src/no-doubled-joshi";
33
import TextLintTester from "textlint-tester";
44
var tester = new TextLintTester();
5+
/*
6+
`**`のような装飾は取り除かれてから評価されているので、
7+
テストでの強調という意味合いのみで利用する。
8+
*/
59
tester.run("no-double-joshi", rule, {
10+
611
valid: [
712
"私は彼が好きだ",
813
"既存のコードの利用", // "の" の例外
@@ -11,9 +16,13 @@ tester.run("no-double-joshi", rule, {
1116
// 、 tokenを距離 + 1 として考える
1217
"右がiPhone、左がAndroidです。",
1318
"ナイフで切断した後、ハンマーで破砕した。",
14-
"まずは試していただいて"
19+
// 接続助詞のてが重複は許容
20+
"まずは試していただいて",
21+
// 1個目の「と」は格助詞、2個めの「と」は接続助詞
22+
"ターミナルで「test」**と**入力する**と**、画面に表示されます。"
1523
],
1624
invalid: [
25+
// エラー位置は最後の助詞の位置を表示する
1726
{
1827
text: "私は彼は好きだ",
1928
errors: [
@@ -122,6 +131,15 @@ tester.run("no-double-joshi", rule, {
122131
column: 16
123132
}
124133
]
134+
}, {
135+
text: "これとあれとそれを持ってきて。",
136+
errors: [
137+
{
138+
message: `一文に二回以上利用されている助詞 "と" がみつかりました。`,
139+
line: 1,
140+
column: 6
141+
}
142+
]
125143
}
126144
]
127145
});

0 commit comments

Comments
 (0)