├── .gitignore ├── test ├── doc │ ├── use-hiragana-and-kanji-properly-v2.md │ ├── numeral-must-be-hankaku.md │ ├── alphabet-must-be-one-byte.md │ ├── dont-use-can-do.md │ ├── kuten.md │ ├── dont-use-kosoado.md │ ├── ka-is-written-in-hiragana.md │ ├── use-assertive-style.md │ ├── use-numeral-properly.md │ ├── symbol.md │ ├── katakana-must-be-two-byte.md │ ├── use-literary-style.md │ └── use-hiragana-and-kanji-properly.md ├── redpen-conf.xml └── script │ ├── kuten.js │ ├── symbol.js │ ├── dont-use-can-do.js │ ├── use-assertive-style.js │ ├── dont-use-kosoado.js │ ├── use-numeral-properly.js │ ├── use-literary-style.js │ ├── numeral-must-be-hankaku.js │ ├── alphabet-must-be-one-byte.js │ ├── ka-is-written-in-hiragana.js │ ├── katakana-must-be-two-byte.js │ ├── use-hiragana-and-kanji-properly.js │ └── use-hiragana-and-kanji-properly-v2.js ├── script └── build_dictionary │ ├── package.json │ └── build-dictionar.js ├── katakana-must-be-two-byte.js ├── alphabet-must-be-one-byte.js ├── numeral-must-be-hankaku.js ├── package.json ├── .codeclimate.yml ├── circle.yml ├── LICENSE ├── ka-is-written-in-hiragana.js ├── symbol.js ├── termsValidator.js ├── custom-pattern.js ├── use-hiragana-and-kanji-properly-v2.js ├── README.md ├── dont-use-can-do.js ├── use-assertive-style.js ├── use-numeral-properly.js ├── use-literary-style.js ├── dont-use-kosoado.js ├── use-joyo-Kanji.js └── use-hiragana-and-kanji-properly.js /.gitignore: -------------------------------------------------------------------------------- 1 | script/*/node_modules 2 | -------------------------------------------------------------------------------- /test/doc/use-hiragana-and-kanji-properly-v2.md: -------------------------------------------------------------------------------- 1 | 学習する上で邪魔です。 2 | -------------------------------------------------------------------------------- /test/doc/numeral-must-be-hankaku.md: -------------------------------------------------------------------------------- 1 | お皿が1枚あります。 2 | 3 | 動物が1匹います 4 | -------------------------------------------------------------------------------- /test/doc/alphabet-must-be-one-byte.md: -------------------------------------------------------------------------------- 1 | ABCは全角です。アルファベットは半角を使わなければなりません。 2 | -------------------------------------------------------------------------------- /test/doc/dont-use-can-do.md: -------------------------------------------------------------------------------- 1 | 勉強することができる 2 | 3 | 勉強することが出来る 4 | 5 | 勉強する事ができた 6 | 7 | 勉強する事が出来る 8 | -------------------------------------------------------------------------------- /test/redpen-conf.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/doc/kuten.md: -------------------------------------------------------------------------------- 1 | # テスト文章。 2 | 3 | ## テスト文章その1。 4 | 5 | - 箇条書きの最後には句点をつけます 6 | - 箇条書きの最後が体言止めの場合は、句点をつけないこと。 7 | - ごはん。 8 | - 美しさ。 9 | 10 | 本文の最後には句点をつけてください 11 | 12 | 丸かっこ(丸かっことは丸かっこのことです。)には句点をつけません。 13 | 14 | 鍵かっこ(鍵カッコとは鍵カッコのことです。)には句点をつけません。 15 | -------------------------------------------------------------------------------- /test/doc/dont-use-kosoado.md: -------------------------------------------------------------------------------- 1 | これはあのご飯です。 2 | 3 | それはご飯です。 4 | 5 | あれはどのご飯です。 6 | 7 | どれがご飯ですか。 8 | 9 | このご飯は何味ですか。 10 | 11 | そのご飯は何味ですか。 12 | 13 | あのご飯は何味ですか。 14 | 15 | どのご飯を食べますか。 16 | 17 | ここは東京都ですか。 18 | 19 | そこは地雷原です。 20 | 21 | あそこは地雷原です。 22 | 23 | 地雷原はどこですか。 24 | 25 | 地雷原はそちらです。 26 | 27 | 地雷原はあちらです。 28 | 29 | どちらに地雷原がありますか。 30 | -------------------------------------------------------------------------------- /test/doc/ka-is-written-in-hiragana.md: -------------------------------------------------------------------------------- 1 | 1ヵ月 2 | 3 | 1カ月 4 | 5 | 1ヶ月 6 | 7 | 1ケ月 8 | 9 | 1箇月 10 | 11 | 1個月 12 | 13 | 1ヵ所 14 | 15 | 1カ所 16 | 17 | 1ヶ所 18 | 19 | 1ケ所 20 | 21 | 1箇所 22 | 23 | 1個所 24 | 25 | 1ヵ国 26 | 27 | 1カ国 28 | 29 | 1ヶ国 30 | 31 | 1ケ国 32 | 33 | 1箇国 34 | 35 | 1個国 36 | 37 | 1ヵ年 38 | 39 | 1カ年 40 | 41 | 1ヶ年 42 | 43 | 1ケ年 44 | 45 | 1箇年 46 | 47 | 1個年 48 | -------------------------------------------------------------------------------- /script/build_dictionary/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "build_dictionary", 3 | "version": "0.0.1", 4 | "description": "", 5 | "main": "build-dictionar.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "kongou-ae", 10 | "license": "MIT", 11 | "dependencies": { 12 | "argv": "0.0.2", 13 | "request": "^2.74.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/doc/use-assertive-style.md: -------------------------------------------------------------------------------- 1 | 元気だと感じた。 2 | 3 | 元気だと感じる。 4 | 5 | 無駄な表現だと考えられる。 6 | 7 | 無駄な表現だと考えられます。 8 | 9 | 高温であることが分かる。 10 | 11 | 高温であることがわかる。 12 | 13 | ご飯を食べたいと思います。 14 | 15 | ご飯を食べたいと思う。 16 | 17 | ご飯を食べたいと思われる。 18 | 19 | あれはご飯かもしれない。 20 | 21 | ご飯を食べるかもしれない 22 | 23 | ご飯を食べるのではないだろうか。 24 | 25 | まず相手の気持ちを知る必要があるでしょう。 26 | 27 | 相手の気持ちを知る必要があるでしょうか。 28 | 29 | わかりやすい 30 | 31 | わかりにくい 32 | 33 | ですが 34 | 35 | 今回は、挑戦しない人ではなく、挑戦したいことがあるのに挑戦できない人です。 36 | -------------------------------------------------------------------------------- /test/doc/use-numeral-properly.md: -------------------------------------------------------------------------------- 1 | # 検知すべき単語 2 | 3 | 三つのボタン 4 | 5 | 第三回大会 6 | 7 | 四か月 8 | 9 | 一番目 10 | 11 | 二進法 12 | 13 | 三次元 14 | 15 | 5大陸 16 | 17 | 1次関数 18 | 19 | 1時的 20 | 21 | # 検知してはいけない単語 22 | 23 | 一言一句 24 | 25 | 1億2805万人 26 | 27 | 3つのボタン 28 | 29 | 第3回大会 30 | 31 | 4か月 32 | 33 | 1番目、2番目 34 | 35 | 2進法 36 | 37 | 3次元 38 | 39 | 四捨五入 40 | 41 | 一汁三菜 42 | 43 | 一期一会 44 | 45 | 世界一 46 | 47 | 一時的 48 | 49 | 一部分 50 | 51 | 第三者 52 | 53 | 一種の 54 | 55 | 一部の 56 | 57 | 一番に 58 | 59 | 数百倍 60 | 61 | 二次関数 62 | 63 | 四捨五入 64 | 65 | 四角い 66 | 67 | 五大陸 68 | -------------------------------------------------------------------------------- /katakana-must-be-two-byte.js: -------------------------------------------------------------------------------- 1 | function validateSentence(sentence) { 2 | // 参考 3 | // https://www.jtf.jp/jp/style_guide/pdf/jtf_style_guide.pdf 4 | // 2.1.5. カタカナ 5 | // カタカナは「全角」で表記します。半角カタカナは特殊な用途を除いて、原則として使いません。 6 | var terms = [ 7 | { 8 | 'expected':'[ァ-ンヲ]', 9 | 'pattern':['[ァ-ンヲ]'] 10 | } 11 | ]; 12 | 13 | var regex = new RegExp( terms[0]['pattern'], 'g'); 14 | // 形態素解析するかどうか 15 | if ( sentence.content.match(regex) ) { 16 | addError('半角のカタカナが含まれています。全角に修正してください', sentence); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /alphabet-must-be-one-byte.js: -------------------------------------------------------------------------------- 1 | function validateSentence(sentence) { 2 | // 参考 3 | // https://www.jtf.jp/jp/style_guide/pdf/jtf_style_guide.pdf 4 | // 2.1.9. アルファベット 5 | // アルファベットは「半角」で表記します。用途によっては全角を許容します。ただし、表記をできるだけ統一するため、特別な理由がない限り半角での表記を原則とします。 6 | 7 | var terms = [ 8 | { 9 | 'expected':'[a-zA-Z]', 10 | 'pattern':['[a-zA-Z]'] 11 | } 12 | ]; 13 | 14 | var regex = new RegExp( terms[0]['pattern'], 'g'); 15 | // 形態素解析するかどうか 16 | if ( sentence.content.match(regex) ) { 17 | addError('全角のアルファベットが含まれています。半角に修正してください', sentence); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /numeral-must-be-hankaku.js: -------------------------------------------------------------------------------- 1 | function validateSentence(sentence) { 2 | // 参考 3 | // https://www.jtf.jp/jp/style_guide/pdf/jtf_style_guide.pdf 4 | // 2.1.8. 算用数字の実装 5 | // 算用数字は「半角」で表記します。用途によっては全角を許容します。ただし、表記をできるだけ統一するため、特別な理由がない限り半角での表記を原則とします。 6 | 7 | var terms = [ 8 | { 9 | 'expected':'[0123456789]', 10 | 'pattern':['[0123456789]'] 11 | } 12 | ]; 13 | 14 | var regex = new RegExp( terms[0]['pattern'], 'g'); 15 | // 形態素解析するかどうか 16 | if ( sentence.content.match(regex) ) { 17 | addError('全角の算用数字が含まれています。半角に修正してください', sentence); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/doc/symbol.md: -------------------------------------------------------------------------------- 1 | かっこ(特にまるかっこ)は全角を使います。 2 | 3 | かっこ(特にまるかっこ)は全角を使います。 4 | 5 | なんですと!? 6 | 7 | なんですと!? 8 | 9 | 小・中学校 10 | 11 | パーソナル・コンピュータ 12 | 13 | 3-5歳の子供です 14 | 15 | - 16 | 17 | 日時:9月10日 18 | 19 | 日時;9月10日 20 | 21 | いわゆる"スマート"な都市 22 | 23 | いわゆる’スマート’な都市 24 | 25 | いわゆる‘スマート’な都市 26 | 27 | 明日{つまり7月20日}は誕生日です。 28 | 29 | 明日<つまり7月20日>は誕生日です。 30 | 31 | 連絡先はy.matsu-moto.ae@gmail.comとy.matsu-moto.ae2@gmail.comです。 32 | 33 | y.matsu-moto.ae@gmail.comとy.matsu-moto.ae2@gmail.com 34 | 35 | 3-5歳の担当者のメールアドレスはy.matsu-moto.ae@gmail.comとy.matsu-moto.ae2@gmail.comです。 36 | 37 | 現在の時刻は17:30です。 38 | 39 | 03-3227-5744 40 | 41 | 東京都中央区1-1-1 42 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "redpen-validator-easy-to-read-japanese-document", 3 | "version": "0.0.5", 4 | "description": "redpen custom validator for writing a easy-to-read japanese document", 5 | "main": "alphabet-must-be-one-byte.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\"" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/kongou-ae/redpen-validator.git" 15 | }, 16 | "keywords": [ 17 | "redpen" 18 | ], 19 | "author": "kongou-ae", 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/kongou-ae/redpen-validator/issues" 23 | }, 24 | "homepage": "https://github.com/kongou-ae/redpen-validator#readme" 25 | } 26 | -------------------------------------------------------------------------------- /test/script/kuten.js: -------------------------------------------------------------------------------- 1 | var expectedResult = 9 2 | var exec = require('child_process').exec; 3 | var fs = require('fs'); 4 | 5 | var r = fs.createReadStream('kuten.js'), 6 | w = fs.createWriteStream('test/kuten.js'); 7 | 8 | r.pipe(w); 9 | w.on('close', function(){ 10 | exec('redpen -c test/redpen-conf.xml test/doc/kuten.md -r json -l 100', function(err, stdout, stderr){ 11 | if (err) throw err; 12 | fs.unlink('test/kuten.js',function(){ 13 | var result = JSON.parse(stdout) 14 | if (result[0].errors.length !== expectedResult){ 15 | throw new Error(result[0].errors.length + " error was occured. It is unexpected.") 16 | } else { 17 | console.log(result[0].errors.length + " error was occured. This is expected.") 18 | } 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /test/script/symbol.js: -------------------------------------------------------------------------------- 1 | var expectedResult = 16; 2 | var exec = require('child_process').exec; 3 | var fs = require('fs'); 4 | 5 | var r = fs.createReadStream('symbol.js'), 6 | w = fs.createWriteStream('test/symbol.js'); 7 | 8 | r.pipe(w); 9 | w.on('close', function(){ 10 | exec('redpen -c test/redpen-conf.xml test/doc/symbol.md -r json -l 100', function(err, stdout, stderr){ 11 | if (err) throw err; 12 | fs.unlink('test/symbol.js',function(){ 13 | var result = JSON.parse(stdout) 14 | if (result[0].errors.length !== expectedResult){ 15 | throw new Error(result[0].errors.length + " error was occured. It is unexpected.") 16 | } else { 17 | console.log(result[0].errors.length + " error was occured. This is expected.") 18 | } 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | engines: 2 | brakeman: 3 | enabled: false 4 | bundler-audit: 5 | enabled: false 6 | csslint: 7 | enabled: false 8 | coffeelint: 9 | enabled: false 10 | duplication: 11 | enabled: false 12 | config: 13 | languages: 14 | - ruby 15 | - javascript 16 | - python 17 | - php 18 | eslint: 19 | enabled: true 20 | fixme: 21 | enabled: false 22 | rubocop: 23 | enabled: false 24 | ratings: 25 | paths: 26 | - Gemfile.lock 27 | - "**.erb" 28 | - "**.haml" 29 | - "**.rb" 30 | - "**.rhtml" 31 | - "**.slim" 32 | - "**.css" 33 | - "**.coffee" 34 | - "**.inc" 35 | - "**.js" 36 | - "**.jsx" 37 | - "**.module" 38 | - "**.php" 39 | - "**.py" 40 | exclude_paths: 41 | - config/**/* 42 | - db/**/* 43 | - spec/**/* 44 | - vendor/**/* -------------------------------------------------------------------------------- /test/doc/katakana-must-be-two-byte.md: -------------------------------------------------------------------------------- 1 | ア 2 | 3 | イ 4 | 5 | ウ 6 | 7 | エ 8 | 9 | オ 10 | 11 | カ 12 | 13 | キ 14 | 15 | ク 16 | 17 | ケ 18 | 19 | コ 20 | 21 | サ 22 | 23 | シ 24 | 25 | ス 26 | 27 | セ 28 | 29 | ソ 30 | 31 | タ 32 | 33 | チ 34 | 35 | ツ 36 | 37 | テ 38 | 39 | ト 40 | 41 | ナ 42 | 43 | ニ 44 | 45 | ヌ 46 | 47 | ネ 48 | 49 | ノ 50 | 51 | ハ 52 | 53 | ヒ 54 | 55 | フ 56 | 57 | ヘ 58 | 59 | ホ 60 | 61 | マ 62 | 63 | ミ 64 | 65 | ム 66 | 67 | メ 68 | 69 | モ 70 | 71 | ヤ 72 | 73 | ユ 74 | 75 | ヨ 76 | 77 | ラ 78 | 79 | リ 80 | 81 | ル 82 | 83 | レ 84 | 85 | ロ 86 | 87 | ワ 88 | 89 | ヲ 90 | 91 | ン 92 | 93 | ァ 94 | 95 | ィ 96 | 97 | ゥ 98 | 99 | ェ 100 | 101 | ォ 102 | 103 | ャ 104 | 105 | ュ 106 | 107 | ョ 108 | 109 | ッ 110 | -------------------------------------------------------------------------------- /test/doc/use-literary-style.md: -------------------------------------------------------------------------------- 1 | あまりにもひどい話だ。 2 | 3 | いっぺんにやってしまおう 4 | 5 | ご飯を食べました。あと、ジュースを飲みました。 6 | 7 | 勉強をやる 8 | 9 | コーチをしてやった 10 | 11 | 明日出かけるけど一緒に来る? 12 | 13 | いい映画だった 14 | 15 | 明日だったら会えますよ 16 | 17 | 狐みたいな狸 18 | 19 | ごはんとかパンとかを食べます 20 | 21 | ごはんじゃなくてパンを食べます 22 | 23 | すごくきれいです 24 | 25 | 超すごい花火でした 26 | 27 | まじですごい花火でした 28 | 29 | パンチをまともにくらってしまった 30 | 31 | パンチをもろにくらった 32 | 33 | 試験は簡単でした。 34 | 35 | 試験は楽でした 36 | 37 | ご飯を食べるのは面倒です。 38 | 39 | このテストは難儀です。 40 | 41 | 厄介な敵にあってしまった。 42 | 43 | 敵を発見すると酸を出して攻撃する性質を持つ。 44 | 45 | わたしは勉強しないといけない。 46 | 47 | わたしはご飯をたべないといけない 48 | 49 | ご飯を食べました。だからご飯を食べましょう。 50 | 51 | ご飯を食べました。それでおなかがいっぱいです。 52 | 53 | すいません。ご飯をとってください。 54 | 55 | ちなみに、明日はご飯を食べますか。 56 | 57 | 雨が降ってます 58 | 59 | 雨が降ってません 60 | 61 | あの白いやつをとってください。 62 | 63 | 赤字になってしまいます。 64 | -------------------------------------------------------------------------------- /test/script/dont-use-can-do.js: -------------------------------------------------------------------------------- 1 | var expectedResult = 4 2 | var exec = require('child_process').exec; 3 | var fs = require('fs'); 4 | 5 | var r = fs.createReadStream('dont-use-can-do.js'), 6 | w = fs.createWriteStream('test/dont-use-can-do.js'); 7 | 8 | r.pipe(w); 9 | w.on('close', function(){ 10 | exec('redpen -c test/redpen-conf.xml test/doc/dont-use-can-do.md -r json -l 100', function(err, stdout, stderr){ 11 | if (err) throw err; 12 | fs.unlink('test/dont-use-can-do.js',function(){ 13 | var result = JSON.parse(stdout) 14 | if (result[0].errors.length !== expectedResult){ 15 | throw new Error(result[0].errors.length + " error was occured. It is unexpected.") 16 | } else { 17 | console.log(result[0].errors.length + " error was occured. This is expected.") 18 | } 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /test/script/use-assertive-style.js: -------------------------------------------------------------------------------- 1 | var expectedResult = 14 2 | var exec = require('child_process').exec; 3 | var fs = require('fs'); 4 | 5 | var r = fs.createReadStream('use-assertive-style.js'), 6 | w = fs.createWriteStream('test/use-assertive-style.js'); 7 | 8 | r.pipe(w); 9 | w.on('close', function(){ 10 | exec('redpen -c test/redpen-conf.xml test/doc/use-assertive-style.md -r json -l 100', function(err, stdout, stderr){ 11 | if (err) throw err; 12 | fs.unlink('test/use-assertive-style.js',function(){ 13 | var result = JSON.parse(stdout) 14 | if (result[0].errors.length !== expectedResult){ 15 | throw new Error(result[0].errors.length + " error was occured. It is unexpected.") 16 | } else { 17 | console.log(result[0].errors.length + " error was occured. This is expected.") 18 | } 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /test/script/dont-use-kosoado.js: -------------------------------------------------------------------------------- 1 | var expectedResult = 2; 2 | var exec = require('child_process').exec; 3 | var fs = require('fs'); 4 | 5 | var r = fs.createReadStream('dont-use-kosoado.js'), 6 | w = fs.createWriteStream('test/dont-use-kosoado.js'); 7 | 8 | r.pipe(w); 9 | w.on('close', function(){ 10 | exec('redpen -c test/redpen-conf.xml test/doc/dont-use-kosoado.md -r json -l 100', function(err, stdout, stderr){ 11 | if (err) throw err; 12 | fs.unlink('test/dont-use-kosoado.js',function(){ 13 | var result = JSON.parse(stdout) 14 | if (result[0].errors.length !== expectedResult){ 15 | throw new Error(result[0].errors.length + " error was occured. It is unexpected.") 16 | } else { 17 | console.log(result[0].errors.length + " error was occured. This is expected.") 18 | } 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /test/script/use-numeral-properly.js: -------------------------------------------------------------------------------- 1 | var expectedResult = 9 2 | var exec = require('child_process').exec; 3 | var fs = require('fs'); 4 | 5 | var r = fs.createReadStream('use-numeral-properly.js'), 6 | w = fs.createWriteStream('test/use-numeral-properly.js'); 7 | 8 | r.pipe(w); 9 | w.on('close', function(){ 10 | exec('redpen -c test/redpen-conf.xml test/doc/use-numeral-properly.md -r json -l 100', function(err, stdout, stderr){ 11 | if (err) throw err; 12 | fs.unlink('test/use-numeral-properly.js',function(){ 13 | var result = JSON.parse(stdout) 14 | if (result[0].errors.length !== expectedResult){ 15 | throw new Error(result[0].errors.length + " error was occured. It is unexpected.") 16 | } else { 17 | console.log(result[0].errors.length + " error was occured. This is expected.") 18 | } 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /test/script/use-literary-style.js: -------------------------------------------------------------------------------- 1 | var expectedResult = 40 2 | var exec = require('child_process').exec; 3 | var fs = require('fs'); 4 | 5 | var r = fs.createReadStream('use-literary-style.js'), 6 | w = fs.createWriteStream('test/use-literary-style.js'); 7 | 8 | r.pipe(w); 9 | w.on('close', function(){ 10 | exec('redpen -c test/redpen-conf.xml test/doc/use-literary-style.md -r json -l 100', function(err, stdout, stderr){ 11 | if (err) throw err; 12 | fs.unlink('test/use-literary-style.js',function(){ 13 | var result = JSON.parse(stdout) 14 | if (result[0].errors.length !== expectedResult){ 15 | throw new Error(result[0].errors.length + " error was occured. It is unexpected.") 16 | } else { 17 | console.log(result[0].errors.length + " error was occured. This is expected.") 18 | } 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /test/script/numeral-must-be-hankaku.js: -------------------------------------------------------------------------------- 1 | var expectedResult = 2; 2 | var exec = require('child_process').exec; 3 | var fs = require('fs'); 4 | 5 | var r = fs.createReadStream('numeral-must-be-hankaku.js'), 6 | w = fs.createWriteStream('test/numeral-must-be-hankaku.js'); 7 | 8 | r.pipe(w); 9 | w.on('close', function(){ 10 | exec('redpen -c test/redpen-conf.xml test/doc/numeral-must-be-hankaku.md -r json -l 100', function(err, stdout, stderr){ 11 | if (err) throw err; 12 | fs.unlink('test/numeral-must-be-hankaku.js',function(){ 13 | var result = JSON.parse(stdout) 14 | if (result[0].errors.length !== expectedResult){ 15 | throw new Error(result[0].errors.length + " error was occured. It is unexpected.") 16 | } else { 17 | console.log(result[0].errors.length + " error was occured. This is expected.") 18 | } 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /test/script/alphabet-must-be-one-byte.js: -------------------------------------------------------------------------------- 1 | var expectedResult = 1; 2 | var exec = require('child_process').exec; 3 | var fs = require('fs'); 4 | 5 | var r = fs.createReadStream('alphabet-must-be-one-byte.js'), 6 | w = fs.createWriteStream('test/alphabet-must-be-one-byte.js'); 7 | 8 | r.pipe(w); 9 | w.on('close', function(){ 10 | exec('redpen -c test/redpen-conf.xml test/doc/alphabet-must-be-one-byte.md -r json -l 100', function(err, stdout, stderr){ 11 | if (err) throw err; 12 | fs.unlink('test/alphabet-must-be-one-byte.js',function(){ 13 | var result = JSON.parse(stdout) 14 | if (result[0].errors.length !== expectedResult){ 15 | throw new Error(result[0].errors.length + " error was occured. It is unexpected.") 16 | } else { 17 | console.log(result[0].errors.length + " error was occured. This is expected.") 18 | } 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /test/script/ka-is-written-in-hiragana.js: -------------------------------------------------------------------------------- 1 | var expectedResult = 24; 2 | var exec = require('child_process').exec; 3 | var fs = require('fs'); 4 | 5 | var r = fs.createReadStream('ka-is-written-in-hiragana.js'), 6 | w = fs.createWriteStream('test/ka-is-written-in-hiragana.js'); 7 | 8 | r.pipe(w); 9 | w.on('close', function(){ 10 | exec('redpen -c test/redpen-conf.xml test/doc/ka-is-written-in-hiragana.md -r json -l 100', function(err, stdout, stderr){ 11 | if (err) throw err; 12 | fs.unlink('test/ka-is-written-in-hiragana.js',function(){ 13 | var result = JSON.parse(stdout) 14 | if (result[0].errors.length !== expectedResult){ 15 | throw new Error(result[0].errors.length + " error was occured. It is unexpected.") 16 | } else { 17 | console.log(result[0].errors.length + " error was occured. This is expected.") 18 | } 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /test/script/katakana-must-be-two-byte.js: -------------------------------------------------------------------------------- 1 | var expectedResult = 55 2 | var exec = require('child_process').exec; 3 | var fs = require('fs'); 4 | 5 | var r = fs.createReadStream('katakana-must-be-two-byte.js'), 6 | w = fs.createWriteStream('test/katakana-must-be-two-byte.js'); 7 | 8 | r.pipe(w); 9 | w.on('close', function(){ 10 | exec('redpen -c test/redpen-conf.xml test/doc/katakana-must-be-two-byte.md -r json -l 100', function(err, stdout, stderr){ 11 | if (err) throw err; 12 | fs.unlink('test/katakana-must-be-two-byte.js',function(){ 13 | var result = JSON.parse(stdout) 14 | if (result[0].errors.length !== expectedResult){ 15 | throw new Error(result[0].errors.length + " error was occured. It is unexpected.") 16 | } else { 17 | console.log(result[0].errors.length + " error was occured. This is expected.") 18 | } 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /test/script/use-hiragana-and-kanji-properly.js: -------------------------------------------------------------------------------- 1 | var expectedResult = 82 2 | var exec = require('child_process').exec; 3 | var fs = require('fs'); 4 | 5 | var r = fs.createReadStream('use-hiragana-and-kanji-properly.js'), 6 | w = fs.createWriteStream('test/use-hiragana-and-kanji-properly.js'); 7 | 8 | r.pipe(w); 9 | w.on('close', function(){ 10 | exec('redpen -c test/redpen-conf.xml test/doc/use-hiragana-and-kanji-properly.md -r json -l 100', function(err, stdout, stderr){ 11 | if (err) throw err; 12 | fs.unlink('test/use-hiragana-and-kanji-properly.js',function(){ 13 | var result = JSON.parse(stdout) 14 | if (result[0].errors.length !== expectedResult){ 15 | throw new Error(result[0].errors.length + " error was occured. It is unexpected.") 16 | } else { 17 | console.log(result[0].errors.length + " error was occured. This is expected.") 18 | } 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /test/script/use-hiragana-and-kanji-properly-v2.js: -------------------------------------------------------------------------------- 1 | var expectedResult = 1 2 | var exec = require('child_process').exec; 3 | var fs = require('fs'); 4 | 5 | var r = fs.createReadStream('use-hiragana-and-kanji-properly-v2.js'), 6 | w = fs.createWriteStream('test/use-hiragana-and-kanji-properly-v2.js'); 7 | 8 | r.pipe(w); 9 | w.on('close', function(){ 10 | exec('redpen -c test/redpen-conf.xml test/doc/use-hiragana-and-kanji-properly-v2.md -r json -l 100', function(err, stdout, stderr){ 11 | if (err) throw err; 12 | fs.unlink('test/use-hiragana-and-kanji-properly-v2.js',function(){ 13 | var result = JSON.parse(stdout) 14 | if (result[0].errors.length !== expectedResult){ 15 | throw new Error(result[0].errors.length + " error was occured. It is unexpected.") 16 | } else { 17 | console.log(result[0].errors.length + " error was occured. This is expected.") 18 | } 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | machine: 2 | environment: 3 | PATH: /home/ubuntu/redpen-validator/redpen-distribution-1.6.2/bin:$PATH 4 | timezone: Asia/Tokyo 5 | java: 6 | version: oraclejdk8 7 | 8 | dependencies: 9 | pre: 10 | - wget https://github.com/redpen-cc/redpen/releases/download/redpen-1.6.2/redpen-1.6.2.tar.gz 11 | - tar xvf redpen-1.6.2.tar.gz 12 | - rm redpen-1.6.2.tar.gz 13 | 14 | test: 15 | post: 16 | - node test/script/alphabet-must-be-one-byte.js 17 | - node test/script/ka-is-written-in-hiragana.js 18 | - node test/script/katakana-must-be-two-byte.js 19 | - node test/script/use-literary-style.js 20 | - node test/script/symbol.js 21 | - node test/script/use-numeral-properly.js 22 | - node test/script/numeral-must-be-hankaku.js 23 | - node test/script/use-hiragana-and-kanji-properly.js 24 | - node test/script/use-assertive-style.js 25 | - node test/script/dont-use-kosoado.js 26 | - node test/script/use-hiragana-and-kanji-properly-v2.js 27 | - node test/script/dont-use-can-do.js 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 kongou-ae 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /test/doc/use-hiragana-and-kanji-properly.md: -------------------------------------------------------------------------------- 1 | 予め用意しておきます。 2 | 3 | 何れわかる時が来ます。 4 | 5 | 何時頃 6 | 7 | 凡そ五営業日です。 8 | 9 | 却って悪化した。 10 | 11 | 且つ、ご飯を食べなければなりません。 12 | 13 | ご飯かも知れない。 14 | 15 | ご飯を食べて下さい。 16 | 17 | これ程おいしいご飯はありません。 18 | 19 | こどもたち、御確認をお願いします。 20 | 21 | 子供は全品半額。更にポイント5倍。然し在庫なし。暫くお待ちください。即ち在庫切れ。折角なので別の店に行く。度々行ったことのある、あのお店に行く。但し、今日は1人で行く。あの人達と一緒ではなく1人で行く。 22 | 23 | 何処でもご飯を食べることが出来る。 24 | 25 | ご飯ないしはパン。尚、麺は含まない。中々困難なルールである。 26 | 27 | ご飯を食べる。又はパンを食べる。寧ろ麺を食べる。滅多に芋は食べない。最早雑食である。 28 | 29 | ご飯を食べる。もしくはパンを食べる。この結果を以て雑食とする。 30 | 31 | この結果を以って雑食とする。 32 | 33 | ご飯を食べる様にパンを食べる人は変態です。余程のことがない限り、好きにはなりません。いっさいの同情を捨てましょう。かならず裏切られます。同情を注ぐのはおおいに結構。しいて言えば無駄です。ときどきむなしくなりませんか。なにしろ変態です。なんらかの結果を抱えています。なんとも言えない欠陥を抱えています。 34 | 35 | 3個所の個条書きをなおしてください。 36 | 37 | 磨耗する 38 | 39 | 磨滅する 40 | 41 | ごはん及びパンを食べる。影響がおよびます 42 | 43 | 御確認をお願い致します。 44 | 45 | 思いをいたします。従って、ルールにしたがってご飯を食べなけれななりません。 46 | 47 | 利子がつきました。 48 | 49 | 以下の通り、2とおりのパターンがほしいので考えて欲しい。 50 | 51 | 余りに邪魔です。極めて邪魔です。様々な障害がありますが、既に全て排除しています。 52 | 53 | 共に敵を排除しよう。例えば、ご飯です。直ちに倒さなければなりません。到底不可能です。果たして勝利できるのでしょうか。一際目立つ戦いです。他の戦いを見る時間はありません。この他の試合は思いの外退屈です。 54 | 55 | 外ならぬあなたの頼みですが、全く賛成できません。元々分かりませんでした。 56 | 57 | 他ならぬあなたの頼みです。 58 | 59 | 私は判りません。我々は一つ一つが解りません。我が闘争。 60 | -------------------------------------------------------------------------------- /script/build_dictionary/build-dictionar.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | // RedpenServerのURL 4 | var respenServerURL = 'http://redpen.herokuapp.com/'; 5 | // 出力で利用するインデント文字 6 | var indentString = ' '; 7 | 8 | var request = require('request'); 9 | var argv = require('argv'); 10 | 11 | var cliOptions = { 12 | name: 'document', 13 | short: 'd', 14 | type: 'string', 15 | description: 'document', 16 | example: "'script --document=value' or 'script -d value'" 17 | }; 18 | 19 | var form = {}; 20 | var args = argv.option(cliOptions).run(); 21 | form.document = args.options.document; 22 | form.lang = 'ja'; 23 | 24 | var requestOptions = { 25 | url: respenServerURL + 'rest/document/tokenize', 26 | method: 'POST', 27 | headers : { 28 | 'Content-Type':'application/x-www-form-urlencoded' 29 | }, 30 | json: true, 31 | form: form 32 | }; 33 | 34 | var tokens = []; 35 | var tokenTags = []; 36 | var tmpDictOjb = {}; 37 | var dictObj = {}; 38 | 39 | request(requestOptions, function (error, response, body) { 40 | if ( error ){ 41 | throw new Error( console.log(error)); 42 | } 43 | 44 | if ( response.statusCode === 200 ) { 45 | for (var i = 0; i < body.tokens.length; i++){ 46 | tokenTags = body.tokens[i].match(/tags=\[(.*)\]/)[1].split(','); 47 | tmpDictOjb = {}; 48 | tmpDictOjb.tags0 = tokenTags[0]; 49 | tmpDictOjb.tags1 = tokenTags[1].replace(/\s/,''); 50 | tmpDictOjb.tags6 = tokenTags[6].replace(/\s/,''); 51 | tokens.push(tmpDictOjb); 52 | 53 | } 54 | dictObj.patern = form.document; 55 | dictObj.tokens = tokens; 56 | console.log(JSON.stringify(dictObj,null,indentString)); 57 | } 58 | }); 59 | -------------------------------------------------------------------------------- /ka-is-written-in-hiragana.js: -------------------------------------------------------------------------------- 1 | function validateSentence(sentence) { 2 | // 参考 3 | // https://www.jtf.jp/jp/style_guide/pdf/jtf_style_guide.pdf 4 | // 2.2.3. 一部の助数詞の表記 5 | // 助数詞にともなう「ヵ」、「か」、「カ」、「ヶ」、「ケ」、「箇」、「個」の表記は、原則として、ひらがなの「か」を使います。 6 | 7 | var terms = [ 8 | { 9 | 'expected':'か', 10 | 'pattern':['ヵ、カ、ヶ、ケ、箇、個'], 11 | 'tokenCheck':['名詞','接尾','[ヵカヶケ箇個][月所国年]'] 12 | }, 13 | { 14 | 'expected':'か月', 15 | 'pattern':['個月'] 16 | } 17 | ]; 18 | 19 | var tokenCheck = function (sentence){ 20 | for (var k = 0; k < sentence.tokens.length; k++) { 21 | if ( 22 | sentence.tokens[k].tags[0] === terms[i]['tokenCheck'][0] && 23 | sentence.tokens[k].tags[1] === terms[i]['tokenCheck'][1] && 24 | sentence.tokens[k].tags[6].match(new RegExp(terms[i]['tokenCheck'][2])) 25 | ){ 26 | addError('「' + sentence.tokens[k].surface + '」を修正してください。助数詞にともなう「ヵかカヶケ箇個」の表記は、原則として、ひらがなの「か」を使います。' , sentence); 27 | } 28 | } 29 | } 30 | 31 | for ( var i = 0; i < terms.length; i++ ) { 32 | for ( var j = 0; j < terms[i]['pattern'].length; j++ ) { 33 | var regex = new RegExp( terms[i]['pattern'][j]); 34 | // 形態素解析するかどうか 35 | if ( 'tokenCheck' in terms[i] ) { 36 | tokenCheck(sentence); 37 | } else { 38 | if ( sentence.content.match(regex) ) { 39 | addError('「' + terms[i]['pattern'][j] + '」を「' + terms[i]['expected'] + '」に修正してください。助数詞にともなう「ヵかカヶケ箇個」の表記は、原則として、ひらがなの「か」を使います。', sentence); 40 | } 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /symbol.js: -------------------------------------------------------------------------------- 1 | function validateSentence(sentence) { 2 | // 参考 3 | // https://www.jtf.jp/jp/style_guide/pdf/jtf_style_guide.pdf 4 | // 4.2. 記号 5 | // カタカナは「全角」で表記します。半角カタカナは特殊な用途を除いて、原則として使いません。 6 | var regex1 = new RegExp( /[()]/ ); 7 | var regex2 = new RegExp( /[!!]/ ); 8 | var regex3 = new RegExp( /[??]/ ); 9 | var regex4 = new RegExp( /[^ァ-ンヲァ-ンヲ]・[^ァ-ンヲァ-ンヲ]/ ); 10 | var regex5 = new RegExp( /[--]/ ); 11 | var regex6 = new RegExp( /[:;:;]/ ); 12 | var regex7 = new RegExp( /["”'’`‘{}{}<>]/ ); 13 | var regexMail = new RegExp(/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*/); 14 | var regexTimes = new RegExp(/([01]?[0-9]|2[0-3])[::]([0-5][0-9])/); 15 | var regexTelNum = new RegExp(/\d{2,5}[-(]\d{1,4}[-)]\d{4}/) 16 | var regexAddress = new RegExp(/[0-9]{1,3}-[0-9]{1,3}-[0-9]{1,3}/) 17 | var tmp = '' 18 | var mailResult = '' 19 | 20 | // 1センテンス内に複数のミスがある場合を考慮して、gつきでマッチさせて、複数回エラーを出した方がいい気がする。 21 | // しかし、複数回ミスがある場合に一つだけ修正すると、残ったミスがエラーとして改めて検知される。 22 | // したがって、とりあえずこのままとする。使ってみて違和感があったらG方式に変更する 23 | if ( sentence.content.match(regex1) ) { 24 | addError('丸かっこは全角を使います。', sentence); 25 | } 26 | if ( sentence.content.match(regex2) ) { 27 | addError('感嘆符の利用は避けてください。', sentence); 28 | } 29 | if ( sentence.content.match(regex3) ) { 30 | addError('疑問符の利用は避けてください。', sentence); 31 | } 32 | if ( sentence.content.match(regex4) ) { 33 | addError('カタカナ複合語の区切り以外で「・」の利用は避けてください。', sentence); 34 | } 35 | 36 | // Sentenceからメールアドレスを除外する 37 | tmp = sentence.content 38 | while ( regexMail.test(tmp) === true ){ 39 | tmp = tmp.replace(regexMail,'') 40 | } 41 | if ( tmp.match(regex5) ){ 42 | if ( !tmp.match(regexTelNum) && !tmp.match(regexAddress)){ 43 | addError('原則として「' + tmp.match(regex5) + '」の利用は避けてください。', sentence); 44 | } 45 | } 46 | 47 | // Sentenceから時刻を除外する 48 | tmp = sentence.content 49 | while ( regexTimes.test(tmp) === true ){ 50 | tmp = tmp.replace(regexTimes,'') 51 | } 52 | if ( tmp.match(regex6) ) { 53 | addError('原則として「' + sentence.content.match(regex6) + '」の利用は避けてください。もし利用せざるを得ない場合は全角を使います。', sentence); 54 | } 55 | if ( sentence.content.match(regex7) ) { 56 | addError('「' + sentence.content.match(regex7) + '」の利用は避けてください。', sentence); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /termsValidator.js: -------------------------------------------------------------------------------- 1 | function validateSentence(sentence) { 2 | // 使い方はREADMEを参照ください。 3 | // https://github.com/kongou-ae/redpen-validator/blob/master/README.md 4 | /* 5 | console = { 6 | log:print 7 | }; 8 | */ 9 | var terms = [ 10 | /* サンプル 11 | { 12 | 'expected':'ファイアウォール', 13 | 'pattern':['ファイアーウォール','ファイヤーウォール','ファイヤウォール','ファイヤーウオール'], 14 | 'source':'MyCompany' 15 | }, 16 | { 17 | 'expected':'こと', 18 | 'pattern':['事'], 19 | 'tokenCheck':['名詞','非自立','事'], 20 | 'source':'MyCompany' 21 | }, 22 | { 23 | 'expected':'なぜ', 24 | 'pattern':['何故'], 25 | 'source':'MyCompany' 26 | }, 27 | { 28 | 'expected':'ちょうど', 29 | 'pattern':['丁度'], 30 | 'source':'MyCompany' 31 | }, 32 | { 33 | 'expected':'なんでも', 34 | 'pattern':['何でも'], 35 | 'source':'MyCompany' 36 | }, 37 | { 38 | 'expected':'通信事業者', 39 | 'pattern':['通信キャリア'], 40 | 'source':'MyCompany' 41 | } 42 | */ 43 | ]; 44 | 45 | var morphologicalAnalysis = function(sentence){ 46 | for (var k = 0; k < sentence.tokens.length; k++) { 47 | if ( sentence.tokens[k].tags[0] === terms[i]['tokenCheck'][0] && 48 | sentence.tokens[k].tags[1] === terms[i]['tokenCheck'][1] && 49 | sentence.tokens[k].tags[6] === terms[i]['tokenCheck'][2] ){ 50 | addError('文書規約違反(' + terms[i]['source'] + ')です。「' + sentence.tokens[k].surface + '」を修正してください。(正:' + terms[i]['expected'] + ' 誤:' + terms[i]['pattern'][j] + ')' , sentence); 51 | } 52 | } 53 | } 54 | 55 | for ( var i = 0; i < terms.length; i++ ) { 56 | for ( var j = 0; j < terms[i]['pattern'].length; j++ ) { 57 | var regex = new RegExp( terms[i]['pattern'][j]); 58 | if ( 'tokenCheck' in terms[i] ) { 59 | morphologicalAnalysis(sentence); 60 | } else { 61 | if ( sentence.content.match(regex) ) { 62 | addError('文書規約違反(' + terms[i]['source'] + ')です。「' + terms[i]['pattern'][j] + '」を「' + terms[i]['expected'] + '」に修正してください', sentence); 63 | } 64 | } 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /custom-pattern.js: -------------------------------------------------------------------------------- 1 | function validateSentence(sentence) { 2 | 3 | var terms = [ 4 | /* // sample 5 | { 6 | 'pattern':'考えられる', 7 | 'message':'断定を避ける表現です。断定系を使ってください。', 8 | 'tokens':[ 9 | { 10 | 'tags0':'動詞', 11 | 'tags1':'自立', 12 | 'tags6':'考える' 13 | }, 14 | { 15 | 'tags0':'動詞', 16 | 'tags1':'接尾', 17 | 'tags6':'られる' 18 | } 19 | ] 20 | }, 21 | { 22 | 'pattern':'ではないだろうか', 23 | 'message':'断定を避ける表現です。断定系を使ってください。', 24 | } 25 | */ 26 | ]; 27 | 28 | var validateRegex = function(sentence,terms){ 29 | var regex = new RegExp( terms.pattern ); 30 | if ( regex.test(sentence) ) { 31 | return 'error'; 32 | } 33 | } 34 | 35 | var validateToken = function(sentence,terms){ 36 | 37 | var result = 0; 38 | for (var i = 0; i < sentence.tokens.length; i++) { 39 | // 検査できる=今のTokenの位置+検査すべきTokenの数が検査すべきTokenの長さよりも小さい 40 | if ( i + terms.tokens.length - 1 < sentence.tokens.length ){ 41 | // 判定用変数を初期化 42 | result = 0 43 | for (var j = 0; j < terms.tokens.length; j++){ 44 | if ( 45 | sentence.tokens[i+j].tags[0] === terms.tokens[j].tags0 && 46 | sentence.tokens[i+j].tags[1] === terms.tokens[j].tags1 && 47 | sentence.tokens[i+j].tags[6] === terms.tokens[j].tags6 48 | ){ 49 | result++; 50 | } 51 | } 52 | if (result === terms.tokens.length){ 53 | return 'error'; 54 | } 55 | } 56 | } 57 | 58 | } 59 | 60 | var error = '' 61 | for (var j = 0; j < terms.length; j++) { 62 | if ( !terms[j].hasOwnProperty('tokens') ){ 63 | error = validateRegex(sentence,terms[j]); 64 | } 65 | 66 | if ( terms[j].hasOwnProperty('tokens') ){ 67 | error = validateToken(sentence,terms[j]); 68 | } 69 | 70 | if ( error ){ 71 | addError( '「' + terms[j].pattern + '」は' + terms[j].message, sentence); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /use-hiragana-and-kanji-properly-v2.js: -------------------------------------------------------------------------------- 1 | function validateSentence(sentence) { 2 | 3 | var terms = [ 4 | /* // sample 5 | { 6 | 'pattern':'考えられる', 7 | 'message':'断定を避ける表現です。断定系を使ってください。', 8 | 'tokens':[ 9 | { 10 | 'tags0':'動詞', 11 | 'tags1':'自立', 12 | 'tags6':'考える' 13 | }, 14 | { 15 | 'tags0':'動詞', 16 | 'tags1':'接尾', 17 | 'tags6':'られる' 18 | } 19 | ] 20 | }, 21 | { 22 | 'pattern':'ではないだろうか', 23 | 'message':'断定を避ける表現です。断定系を使ってください。', 24 | } 25 | */ 26 | { 27 | "patern": "上で", 28 | 'message':'「上で」を「うえで」に修正してください。', 29 | "tokens": [ 30 | { 31 | "tags0": "名詞", 32 | "tags1": "非自立", 33 | "tags6": "上" 34 | }, 35 | { 36 | "tags0": "助詞", 37 | "tags1": "格助詞", 38 | "tags6": "で" 39 | } 40 | ] 41 | } 42 | ]; 43 | 44 | var validateRegex = function(sentence,terms){ 45 | var regex = new RegExp( terms.pattern ); 46 | if ( regex.test(sentence) ) { 47 | return 'error'; 48 | } 49 | } 50 | 51 | var validateToken = function(sentence,terms){ 52 | 53 | var result = 0; 54 | for (var i = 0; i < sentence.tokens.length; i++) { 55 | // 検査できる=今のTokenの位置+検査すべきTokenの数が検査すべきTokenの長さよりも小さい 56 | if ( i + terms.tokens.length - 1 < sentence.tokens.length ){ 57 | // 判定用変数を初期化 58 | result = 0 59 | for (var j = 0; j < terms.tokens.length; j++){ 60 | if ( 61 | sentence.tokens[i+j].tags[0] === terms.tokens[j].tags0 && 62 | sentence.tokens[i+j].tags[1] === terms.tokens[j].tags1 && 63 | sentence.tokens[i+j].tags[6] === terms.tokens[j].tags6 64 | ){ 65 | result++; 66 | } 67 | } 68 | if (result === terms.tokens.length){ 69 | return 'error'; 70 | } 71 | } 72 | } 73 | 74 | } 75 | 76 | var error = '' 77 | for (var j = 0; j < terms.length; j++) { 78 | if ( !terms[j].hasOwnProperty('tokens') ){ 79 | error = validateRegex(sentence,terms[j]); 80 | } 81 | 82 | if ( terms[j].hasOwnProperty('tokens') ){ 83 | error = validateToken(sentence,terms[j]); 84 | } 85 | 86 | if ( error ){ 87 | addError( '「' + terms[j].pattern + '」は' + terms[j].message, sentence); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # redpen-validator 2 | 3 | Javascript拡張を利用したRedPenのValidatorです。 4 | 5 | ![](https://circleci.com/gh/kongou-ae/redpen-validator.svg?style=shield&circle-token=%206c4f0d89b0efed4089120942326e94013006d1c2) [![Code Climate](https://codeclimate.com/github/kongou-ae/redpen-validator/badges/gpa.svg)](https://codeclimate.com/github/kongou-ae/redpen-validator) 6 | 7 | # 使い方 8 | 9 | RedPenのコンフィグファイルに以下を追記します。 10 | 11 | ```xml 12 | 13 | 14 | 15 | ``` 16 | 17 | ## 各ファイルが対応する検査項目 18 | 19 | |ファイル名 |検査項目 |参考文献 | 20 | |----------------------------|--------------------------|-----------------------| 21 | |use-joyo-Kanji.js |常用漢字を使っているか |JTF 日本語標準スタイルガイド(翻訳用) 2.1.2| 22 | |katakana-must-be-two-byte.js|全角のカタカナを使っているか |JTF 日本語標準スタイルガイド(翻訳用) 2.1.5| 23 | |numeral-must-be-hankaku.js |半角の算用数字を使っているか |JTF 日本語標準スタイルガイド(翻訳用) 2.1.8| 24 | |alphabet-must-be-one-byte.js|半角のアルファベットを使っているか |JTF 日本語標準スタイルガイド(翻訳用) 2.1.9| 25 | |use-hiragana-and-kanji-properly.js |ひらがなと漢字の使い分け|JTF 日本語標準スタイルガイド(翻訳用) 2.2.1| 26 | |use-numeral-properly.js |算用数字と漢数字の使い分け   |JTF 日本語標準スタイルガイド(翻訳用) 2.2.2| 27 | |ka-is-written-in-hiragana.js|助数詞にともなう「か」の表記 |JTF 日本語標準スタイルガイド(翻訳用) 2.2.3| 28 | |symbol.js |記号の使い方が適切か |JTF 日本語標準スタイルガイド(翻訳用) 4.2 & 4.3| 29 | |use-assertive-style.js |断定を避ける表現 |use-assertive-style.js内に記載| 30 | |use-literary-style.js    |口語表現 |use-literary-style.js内に記載 | 31 | |dont-use-kosoado.js |こそあど言葉 |dont-use-kosoado.js内に記載 | 32 | |dont-use-can-do.js |することができる |dont-use-can-do.js内に記載 | 33 | |custom-pattern.js |自分で登録した規則が含まれているか  |なし 34 | 35 | 36 | 37 | ## custom-pattern.js 38 | 39 | 自分で表記の規則を登録して利用する拡張です。`terms`配列に登録されている表記の規則を利用して、文章に規則から外れた表現が含まれているかを検査します。検査方法は正規表現と形態素解析の二つをサポートしています。 40 | 41 | ### 正規表現による検査 42 | 43 | 正規表現による検査を行う場合、`terms`配列に以下パラメータを持ったオブジェクトを登録します。 44 | 45 | ``` 46 | { 47 | 'pattern':'ではないだろうか', 48 | 'message':'断定を避ける表現です。断定系を使ってください。', 49 | } 50 | ``` 51 | 52 | ### 形態素解析による検査 53 | 54 | 形態素解析による検査を行う場合、`terms`配列に以下プロパティを持ったオブジェクトを登録します。 55 | 56 | ``` 57 | { 58 | 'pattern':'考えられる', 59 | 'message':'断定を避ける表現です。断定系を使ってください。', 60 | 'tokens':[ 61 | { 62 | 'tags0':'動詞', 63 | 'tags1':'自立', 64 | 'tags6':'考える' 65 | }, 66 | { 67 | 'tags0':'動詞', 68 | 'tags1':'接尾', 69 | 'tags6':'られる' 70 | } 71 | ] 72 | }, 73 | ``` 74 | 75 | `tokens`プロパティには、kuromojiによる形態素解析の結果を登録します。各項目とkuromojiによる形態素解析の結果は、以下の通り紐づいています。kuromojiによる形態素解析の結果は[kuromojiのデモサイト](http://atilika.org/kuromoji/)で取得するのが簡単です。 76 | 77 | |項目 |登録内容| 78 | |------|-------| 79 | |tags0 |`Part-of-Speech`の1つ目(kuromojiが生成するTokenに含まれるFeatureの1つ目)| 80 | |tags1 |`Part-of-Speech`の2つ目(kuromojiが生成するTokenに含まれるFeatureの2つ目)| 81 | |tags6 |`Base form`(kuromojiが生成するTokenに含まれるFeatureの7つ目)| 82 | 83 | ## 謝辞 84 | 85 | use-joyo-Kanji.jsの作成にあたっては、以下のサイトを参考にさせていただきました。感謝します。 86 | 87 | - [【みんなの知識 ちょっと便利帳】入力した文章・文字が常用漢字かどうかを調べる](http://www.benricho.org/kanji/kyoikukanji/check-jyoyo-kanji.html) 88 | - [漢字にマッチする JavaScript の正規表現パターン: Days on the Moon](http://nanto.asablo.jp/blog/2015/12/31/7966713) 89 | -------------------------------------------------------------------------------- /dont-use-can-do.js: -------------------------------------------------------------------------------- 1 | function validateSentence(sentence) { 2 | // 参考 3 | // http://www.slideshare.net/yoshinobumachida5/lets-write-understandable-japanese-complete-version 4 | // することができる問題 5 | var terms = [ 6 | { 7 | "pattern": "することができる", 8 | "message": "冗長な表現です。", 9 | "tokens": [ 10 | { 11 | "tags0": "動詞", 12 | "tags1": "自立", 13 | "tags6": "する" 14 | }, 15 | { 16 | "tags0": "名詞", 17 | "tags1": "非自立", 18 | "tags6": "こと" 19 | }, 20 | { 21 | "tags0": "助詞", 22 | "tags1": "格助詞", 23 | "tags6": "が" 24 | }, 25 | { 26 | "tags0": "動詞", 27 | "tags1": "自立", 28 | "tags6": "できる" 29 | } 30 | ] 31 | }, 32 | { 33 | "pattern": "することが出来る", 34 | "message": "冗長な表現です。", 35 | "tokens": [ 36 | { 37 | "tags0": "動詞", 38 | "tags1": "自立", 39 | "tags6": "する" 40 | }, 41 | { 42 | "tags0": "名詞", 43 | "tags1": "非自立", 44 | "tags6": "こと" 45 | }, 46 | { 47 | "tags0": "助詞", 48 | "tags1": "格助詞", 49 | "tags6": "が" 50 | }, 51 | { 52 | "tags0": "動詞", 53 | "tags1": "自立", 54 | "tags6": "出来る" 55 | } 56 | ] 57 | }, 58 | { 59 | "pattern": "する事ができる", 60 | "message": "冗長な表現です。", 61 | "tokens": [ 62 | { 63 | "tags0": "動詞", 64 | "tags1": "自立", 65 | "tags6": "する" 66 | }, 67 | { 68 | "tags0": "名詞", 69 | "tags1": "非自立", 70 | "tags6": "事" 71 | }, 72 | { 73 | "tags0": "助詞", 74 | "tags1": "格助詞", 75 | "tags6": "が" 76 | }, 77 | { 78 | "tags0": "動詞", 79 | "tags1": "自立", 80 | "tags6": "できる" 81 | } 82 | ] 83 | }, 84 | { 85 | "pattern": "することが出来る", 86 | "message": "冗長な表現です。", 87 | "tokens": [ 88 | { 89 | "tags0": "動詞", 90 | "tags1": "自立", 91 | "tags6": "する" 92 | }, 93 | { 94 | "tags0": "名詞", 95 | "tags1": "非自立", 96 | "tags6": "事" 97 | }, 98 | { 99 | "tags0": "助詞", 100 | "tags1": "格助詞", 101 | "tags6": "が" 102 | }, 103 | { 104 | "tags0": "動詞", 105 | "tags1": "自立", 106 | "tags6": "出来る" 107 | } 108 | ] 109 | } 110 | ]; 111 | 112 | var validateRegex = function(sentence,terms){ 113 | var regex = new RegExp( terms.pattern ); 114 | if ( regex.test(sentence) ) { 115 | return 'error'; 116 | } 117 | } 118 | 119 | var validateToken = function(sentence,terms){ 120 | var result = 0; 121 | for (var i = 0; i < sentence.tokens.length; i++) { 122 | // 検査できる=今のTokenの位置+検査すべきTokenの数が検査すべきTokenの長さよりも小さい 123 | if ( i + terms.tokens.length - 1 < sentence.tokens.length ){ 124 | // 判定用変数を初期化 125 | result = 0 126 | for (var j = 0; j < terms.tokens.length; j++){ 127 | if ( 128 | sentence.tokens[i+j].tags[0] === terms.tokens[j].tags0 && 129 | sentence.tokens[i+j].tags[1] === terms.tokens[j].tags1 && 130 | sentence.tokens[i+j].tags[6] === terms.tokens[j].tags6 131 | ){ 132 | result++; 133 | } 134 | } 135 | if (result === terms.tokens.length){ 136 | return 'error'; 137 | } 138 | } 139 | } 140 | } 141 | 142 | var error = '' 143 | for (var j = 0; j < terms.length; j++) { 144 | if ( !terms[j].hasOwnProperty('tokens') ){ 145 | error = validateRegex(sentence,terms[j]); 146 | } 147 | 148 | if ( terms[j].hasOwnProperty('tokens') ){ 149 | error = validateToken(sentence,terms[j]); 150 | } 151 | 152 | if ( error ){ 153 | addError( '「' + terms[j].pattern + '」は' + terms[j].message, sentence); 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /use-assertive-style.js: -------------------------------------------------------------------------------- 1 | function validateSentence(sentence) { 2 | 3 | var terms = [ 4 | { 5 | 'pattern':'考えられる', 6 | 'message':'断定を避ける表現です。断定系を使ってください。', 7 | 'tokens':[ 8 | { 9 | 'tags0':'動詞', 10 | 'tags1':'自立', 11 | 'tags6':'考える' 12 | }, 13 | { 14 | 'tags0':'動詞', 15 | 'tags1':'接尾', 16 | 'tags6':'られる' 17 | } 18 | ] 19 | }, 20 | { 21 | 'pattern':'が分かる', 22 | 'message':'断定を避ける表現です。断定系を使ってください。', 23 | 'tokens':[ 24 | { 25 | 'tags0':'助詞', 26 | 'tags1':'格助詞', 27 | 'tags6':'が' 28 | }, 29 | { 30 | 'tags0':'動詞', 31 | 'tags1':'自立', 32 | 'tags6':'分かる' 33 | } 34 | ] 35 | }, 36 | { 37 | 'pattern':'がわかる', 38 | 'message':'断定を避ける表現です。断定系を使ってください。', 39 | 'tokens':[ 40 | { 41 | 'tags0':'助詞', 42 | 'tags1':'格助詞', 43 | 'tags6':'が' 44 | }, 45 | { 46 | 'tags0':'動詞', 47 | 'tags1':'自立', 48 | 'tags6':'わかる' 49 | } 50 | ] 51 | }, 52 | { 53 | 'pattern':'と思う', 54 | 'message':'断定を避ける表現です。断定系を使ってください。', 55 | 'tokens':[ 56 | { 57 | 'tags0':'助詞', 58 | 'tags1':'格助詞', 59 | 'tags6':'と' 60 | }, 61 | { 62 | 'tags0':'動詞', 63 | 'tags1':'自立', 64 | 'tags6':'思う' 65 | } 66 | ] 67 | }, 68 | { 69 | 'pattern':'かもしれない', 70 | 'message':'断定を避ける表現です。断定系を使ってください。', 71 | 'tokens':[ 72 | { 73 | 'tags0':'助詞', 74 | 'tags1':'副助詞', 75 | 'tags6':'かも' 76 | }, 77 | { 78 | 'tags0':'動詞', 79 | 'tags1':'自立', 80 | 'tags6':'しれる' 81 | }, 82 | { 83 | 'tags0':'助動詞', 84 | 'tags1':'*', 85 | 'tags6':'ない' 86 | } 87 | ] 88 | }, 89 | { 90 | 'pattern':'ではないだろうか', 91 | 'message':'断定を避ける表現です。断定系を使ってください。' 92 | }, 93 | { 94 | 'pattern':'でしょう', 95 | 'message':'断定を避ける表現です。断定系を使ってください。' 96 | }, 97 | { 98 | 'pattern':'と感じる', 99 | 'message':'断定を避ける表現です。断定系を使ってください。', 100 | 'tokens':[ 101 | { 102 | 'tags0':'助詞', 103 | 'tags1':'格助詞', 104 | 'tags6':'と' 105 | }, 106 | { 107 | 'tags0':'動詞', 108 | 'tags1':'自立', 109 | 'tags6':'感じる' 110 | } 111 | ] 112 | } 113 | ]; 114 | 115 | var validateRegex = function(sentence,terms){ 116 | var regex = new RegExp( terms.pattern ); 117 | if ( regex.test(sentence) ) { 118 | return 'error'; 119 | } 120 | } 121 | 122 | var validateToken = function(sentence,terms){ 123 | var result = 0; 124 | for (var i = 0; i < sentence.tokens.length; i++) { 125 | // 検査できる=今のTokenの位置+検査すべきTokenの数が検査すべきTokenの長さよりも小さい 126 | if ( i + terms.tokens.length - 1 < sentence.tokens.length ){ 127 | // 判定用変数を初期化 128 | result = 0 129 | for (var j = 0; j < terms.tokens.length; j++){ 130 | // 過剰検知は先行でresultを減らすことで対処 131 | if (sentence.tokens[i+j].tags[6] === "わかる" && sentence.tokens[i+j+1].tags[0] === "形容詞"){ result--; } 132 | if (sentence.tokens[i+j].tags[6] === "分かる" && sentence.tokens[i+j+1].tags[0] === "形容詞"){ result--; } 133 | 134 | if ( 135 | sentence.tokens[i+j].tags[0] === terms.tokens[j].tags0 && 136 | sentence.tokens[i+j].tags[1] === terms.tokens[j].tags1 && 137 | sentence.tokens[i+j].tags[6] === terms.tokens[j].tags6 138 | ){ 139 | result++; 140 | } 141 | } 142 | if (result === terms.tokens.length){ 143 | return 'error'; 144 | } 145 | } 146 | } 147 | } 148 | 149 | var error = '' 150 | for (var j = 0; j < terms.length; j++) { 151 | if ( !terms[j].hasOwnProperty('tokens') ){ 152 | error = validateRegex(sentence,terms[j]); 153 | } 154 | 155 | if ( terms[j].hasOwnProperty('tokens') ){ 156 | error = validateToken(sentence,terms[j]); 157 | } 158 | 159 | if ( error ){ 160 | addError( '「' + terms[j].pattern + '」は' + terms[j].message, sentence); 161 | } 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /use-numeral-properly.js: -------------------------------------------------------------------------------- 1 | function validateSentence(sentence) { 2 | // 参考 3 | // https://www.jtf.jp/jp/style_guide/pdf/jtf_style_guide.pdf 4 | // 2.2.2. 算用数字と漢数字の使い分け 5 | // 数量を表現し、数を数えられるものは算用数字を使用します。任意の数に置き換えても通用する語句がこれに該当します。序数詞(「第~回」「~番目」「~回目」)も算用数字を使います。 6 | var tmp = '' 7 | for (var k = 0; k < sentence.tokens.length; k++) { 8 | 9 | // -------------------------------------------------------------------------------------------- 10 | // -漢数字にすべきなのに、算用数字になってしまうケースを除外する 11 | // -------------------------------------------------------------------------------------------- 12 | // 3文字先までチェックして4文字熟語であれば、算用数字にしない(4個のTokenに分割されない4文字熟語は別途考える。。) 13 | 14 | if ( k + 3 < sentence.tokens.length ) { 15 | if ( 16 | sentence.tokens[k].tags[6].match(/[一二三四五六七八九十百千]/) && 17 | sentence.tokens[k+1].tags[6].match(/[\u4E00-\u9FFF]/) && 18 | sentence.tokens[k+2].tags[6].match(/[一二三四五六七八九十百千]/) && 19 | sentence.tokens[k+3].tags[6].match(/[\u4E00-\u9FFF]/) 20 | ) return null; 21 | } 22 | 23 | // 4文字にTokenされす3文字にTokenされる四文字熟語を算用数字にしない 24 | if ( k + 2 < sentence.tokens.length ) { 25 | tmp = sentence.tokens[k].surface + sentence.tokens[k+1].surface + sentence.tokens[k+2].surface; 26 | if ( tmp.match(/[一二三四五六七八九十百千][\u4E00-\u9FFF][一二三四五六七八九十百千][\u4E00-\u9FFF]/) ) return null; 27 | } 28 | 29 | // 4文字にTokenされす2文字にTokenされる四文字熟語を算用数字にしない 30 | if ( k + 1 < sentence.tokens.length ){ 31 | tmp = sentence.tokens[k].surface + sentence.tokens[k+1].surface; 32 | if ( tmp.match(/[一二三四五六七八九十百千][\u4E00-\u9FFF][一二三四五六七八九十百千][\u4E00-\u9FFF]/) ) return null; 33 | } 34 | 35 | // 数[漢数字]が数[算用数字]になってしまうので除外 36 | if ( k + 1 < sentence.tokens.length ){ 37 | if ( 38 | sentence.tokens[k].tags[6] === '数' && 39 | sentence.tokens[k+1].tags[6].match(/[十百千万]/) 40 | ) return null; 41 | } 42 | 43 | // [漢数字]次[名詞] 44 | if (k + 2 < sentence.tokens.length){ 45 | if ( 46 | sentence.tokens[k].tags[6].match(new RegExp(/[一二三四五六七八九十百千]/)) && 47 | sentence.tokens[k+1].tags[6] === '次' && 48 | sentence.tokens[k+2].tags[0] === '名詞' 49 | ) return null; 50 | } 51 | 52 | if( k + 1 < sentence.tokens.length ){ 53 | if ( 54 | sentence.tokens[k].surface === '五' && 55 | sentence.tokens[k+1].tags[6] ==='大陸' 56 | ) return null; 57 | } 58 | 59 | // -------------------------------------------------------------------------------------------- 60 | // 最後の処理で算用数字にすべきなのに、ならないケースを個別にエラー処理 61 | // -------------------------------------------------------------------------------------------- 62 | // 漢数字を含む言葉が一つの単語としてtokenizeされてしまうになってしまうケース 63 | if ( sentence.tokens[k].tags[6].match(/十進法|二進法|十六進法/) ) return addError('数を数えられるものは算用数字を利用します' , sentence ); 64 | 65 | // 三つが「三つ」という一般名詞でtokenizeされてしまうので、個別に定義 66 | if ( 67 | sentence.tokens[k].tags[0] === "名詞" && 68 | sentence.tokens[k].tags[1] === "一般" && 69 | sentence.tokens[k].tags[6].match(new RegExp(/[一二三四五六七八九]つ/)) 70 | ){ 71 | addError('数を数えられるものは算用数字を利用します' , sentence ); 72 | } 73 | 74 | // -------------------------------------------------------------------------------------------- 75 | // 問答無用で算用数字にする処理 76 | // -------------------------------------------------------------------------------------------- 77 | // 上記に合致せず、名詞で数のものがあれば、 78 | if ( 79 | sentence.tokens[k].tags[0] === "名詞" && 80 | sentence.tokens[k].tags[1] === "数" && 81 | sentence.tokens[k].tags[6].match(new RegExp(/[一二三四五六七八九十百千]/)) 82 | ){ 83 | addError('数を数えられるものは算用数字を利用します' , sentence ); 84 | } 85 | 86 | // -------------------------------------------------------------------------------------------- 87 | // 漢数字にすべきケースに対してエラー処理 88 | // -------------------------------------------------------------------------------------------- 89 | // [漢数字]大陸 算用数字の場合は、漢数字にするよう促す 90 | if ( k + 1 < sentence.tokens.length ){ 91 | if ( 92 | sentence.tokens[k].surface === '5' && 93 | sentence.tokens[k+1].tags[6] ==='大陸' 94 | ) addError('慣用的表現、熟語、概数、固有名詞、副詞など、漢数字を使用することが一般的な語句では漢数字を使います。' , sentence ); 95 | } 96 | 97 | // [算用数字]次[名詞] 98 | if ( k + 2 < sentence.tokens.length ){ 99 | if ( 100 | sentence.tokens[k].surface.match(new RegExp(/[1-9]/)) && 101 | sentence.tokens[k+1].tags[6] === '次' && 102 | sentence.tokens[k+2].tags[0] === '名詞' 103 | ) addError('慣用的表現、熟語、概数、固有名詞、副詞など、漢数字を使用することが一般的な語句では漢数字を使います。' , sentence ); 104 | } 105 | 106 | // [算用数字]時的 107 | if ( k + 2 < sentence.tokens.length ){ 108 | if ( 109 | sentence.tokens[k].surface.match(new RegExp(/[1-9]/)) && 110 | sentence.tokens[k+1].tags[6] === '時' && 111 | sentence.tokens[k+2].tags[6] === '的' 112 | ) addError('慣用的表現、熟語、概数、固有名詞、副詞など、漢数字を使用することが一般的な語句では漢数字を使います。' , sentence ); 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /use-literary-style.js: -------------------------------------------------------------------------------- 1 | function validateSentence(sentence) { 2 | // 口語ではなく文語を使う 3 | 4 | var terms = [ 5 | // http://www.ise.chuo-u.ac.jp/ISE/outline/Gmajor/nihongo/28.html 6 | { 7 | 'expected':'過度に', 8 | 'pattern':['あまりに'] 9 | }, 10 | { 11 | 'expected':'一度に/一括して/まとめて', 12 | 'pattern':['いっぺんに'] 13 | }, 14 | { 15 | 'expected':'また,さらに', 16 | 'pattern':['あと'], 17 | 'tokenCheck':['名詞','副詞可能','あと'] 18 | }, 19 | { 20 | 'expected':'行う/する', 21 | 'pattern':['やる'], 22 | 'tokenCheck':['動詞','自立','やる'] 23 | }, 24 | { 25 | 'expected':'する', 26 | 'pattern':['してやる'], 27 | 'tokenCheck':['動詞','自立','してやる'] 28 | }, 29 | // 別途検知方法を考える 30 | // してあげる、してない 31 | { 32 | 'expected':'が', 33 | 'pattern':['けど'], 34 | 'tokenCheck':['助詞','接続助詞','けど'] 35 | }, 36 | { 37 | 'expected':'であった', 38 | 'pattern':['だった'] 39 | }, 40 | { 41 | 'expected':'であるとき/であったらならば/なら', 42 | 'pattern':['だったら'] 43 | }, 44 | // 別途検知方法を考える 45 | // 文頭のシリーズ しようがない 46 | { 47 | 'expected':'のような', 48 | 'pattern':['みたいな'] 49 | }, 50 | { 51 | 'expected':'は/や', 52 | 'pattern':['とか'], 53 | 'tokenCheck':['助詞','並立助詞','とか'] 54 | }, 55 | // 別途検知方法を考える 56 | // したり 57 | { 58 | 'expected':'ではなく', 59 | 'pattern':['じゃなくて'] 60 | }, 61 | { 62 | 'expected':'適切な言葉', 63 | 'pattern':['すごく'], 64 | 'tokenCheck':['形容詞','自立','すごい'] 65 | }, 66 | // 別途検知方法を考える 67 | // したり 68 | { 69 | 'expected':'比較的/やや/かなり/たいへん/きわめて', 70 | 'pattern':['超'], 71 | 'tokenCheck':['接頭詞','名詞接続','超'] 72 | }, 73 | { 74 | 'expected':'真に/絶対的に/圧倒的に', 75 | 'pattern':['まじで'] 76 | }, 77 | { 78 | 'expected':'直接的に/直接', 79 | 'pattern':['まともに'] 80 | }, 81 | { 82 | 'expected':'直接的に/直接', 83 | 'pattern':['もろに'] 84 | }, 85 | { 86 | 'expected':'単純/易しい/容易', 87 | 'pattern':['簡単'] 88 | }, 89 | { 90 | 'expected':'単純/易しい/容易', 91 | 'pattern':['楽'], 92 | 'tokenCheck':['名詞','形容動詞語幹','楽'] 93 | }, 94 | { 95 | 'expected':'複雑/難しい/困難', 96 | 'pattern':['面倒'] 97 | }, 98 | { 99 | 'expected':'複雑/難しい/困難', 100 | 'pattern':['難儀'] 101 | }, 102 | { 103 | 'expected':'複雑/難しい/困難', 104 | 'pattern':['厄介'] 105 | }, 106 | // http://www.ipentec.com/document/document.aspx?page=write-thesis-tips 107 | /* 108 | { 109 | 'expected':'別の表現', 110 | 'pattern':['という'], 111 | 'tokenCheck':['助詞','格助詞','という'] 112 | }, 113 | */ 114 | { 115 | 'expected':'別の表現', 116 | 'pattern':['すると'] 117 | }, 118 | // http://isabelle.cc.kyushu-u.ac.jp/~amano/how_to_write/japanese.html 119 | { 120 | 'expected':'する必要がある', 121 | 'pattern':['ないといけない'] 122 | }, 123 | { 124 | 'expected':'したがって/このため/そのため', 125 | 'pattern':['だから'] 126 | }, 127 | { 128 | 'expected':'したがって/このため/そのため', 129 | 'pattern':['それで'] 130 | }, 131 | // http://www.ise.chuo-u.ac.jp/ISE/outline/Gmajor/nihongo/50.html 132 | { 133 | 'expected':'済みません/申し訳ございません', 134 | 'pattern':['すいません'] 135 | }, 136 | { 137 | 'expected':'他の適切な表現', 138 | 'pattern':['ちなみに'] 139 | }, 140 | { 141 | 'expected':'ています', 142 | 'pattern':['てます'] 143 | }, 144 | { 145 | 'expected':'ていません', 146 | 'pattern':['てません'] 147 | }, 148 | { 149 | 'expected':'もの', 150 | 'pattern':['やつ'], 151 | 'tokenCheck':['名詞','代名詞','やつ'] 152 | }, 153 | { 154 | 'expected':'削除/他の適切な表現', 155 | 'pattern':['しまう'], 156 | 'tokenCheck':['動詞','非自立','しまう'] 157 | } 158 | ]; 159 | 160 | var morphologicalAnalysis = function(sentence){ 161 | for (var k = 0; k < sentence.tokens.length; k++) { 162 | if ( sentence.tokens[k].tags[0] === terms[i]['tokenCheck'][0] && 163 | sentence.tokens[k].tags[1] === terms[i]['tokenCheck'][1] && 164 | sentence.tokens[k].tags[6] === terms[i]['tokenCheck'][2] ){ 165 | addError('「' + terms[i]['pattern'][j] +'」は口語です。「' + terms[i]['expected'] + '」に修正してください' , sentence); 166 | } 167 | } 168 | } 169 | 170 | for ( var i = 0; i < terms.length; i++ ) { 171 | for ( var j = 0; j < terms[i]['pattern'].length; j++ ) { 172 | var regex = new RegExp( terms[i]['pattern'][j] ); 173 | if ( 'tokenCheck' in terms[i] ) { 174 | morphologicalAnalysis(sentence); 175 | } else { 176 | if ( sentence.content.match(regex) ) { 177 | addError('「' + terms[i]['pattern'][j] +'」は口語です。「' + terms[i]['expected'] + '」に修正してください。' , sentence); 178 | } 179 | } 180 | } 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /dont-use-kosoado.js: -------------------------------------------------------------------------------- 1 | function validateSentence(sentence) { 2 | // 参考 3 | // http://jubilee-web.jp/blog/archives/96 4 | var terms = [ 5 | { 6 | "pattern": "これ", 7 | "message": "指示語です。指示語を使うと文章が分かりにくくなります。具体的な表現を検討してください。", 8 | "tokens": [ 9 | { 10 | "tags0": "名詞", 11 | "tags1": "代名詞", 12 | "tags6": "これ" 13 | } 14 | ] 15 | }, 16 | { 17 | "pattern": "それ", 18 | "message": "指示語です。指示語を使うと文章が分かりにくくなります。具体的な表現を検討してください。", 19 | "tokens": [ 20 | { 21 | "tags0": "名詞", 22 | "tags1": "代名詞", 23 | "tags6": "それ" 24 | } 25 | ] 26 | }, 27 | { 28 | "pattern": "あれ", 29 | "message": "指示語です。指示語を使うと文章が分かりにくくなります。具体的な表現を検討してください。", 30 | "tokens": [ 31 | { 32 | "tags0": "名詞", 33 | "tags1": "代名詞", 34 | "tags6": "あれ" 35 | } 36 | ] 37 | }, 38 | { 39 | "pattern": "どれ", 40 | "message": "指示語です。指示語を使うと文章が分かりにくくなります。具体的な表現を検討してください。", 41 | "tokens": [ 42 | { 43 | "tags0": "名詞", 44 | "tags1": "代名詞", 45 | "tags6": "どれ" 46 | } 47 | ] 48 | }, 49 | { 50 | "pattern": "この", 51 | "message": "指示語です。指示語を使うと文章が分かりにくくなります。具体的な表現を検討してください。", 52 | "tokens": [ 53 | { 54 | "tags0": "連体詞", 55 | "tags1": "*", 56 | "tags6": "この" 57 | } 58 | ] 59 | }, 60 | { 61 | "pattern": "その", 62 | "message": "指示語です。指示語を使うと文章が分かりにくくなります。具体的な表現を検討してください。", 63 | "tokens": [ 64 | { 65 | "tags0": "連体詞", 66 | "tags1": "*", 67 | "tags6": "その" 68 | } 69 | ] 70 | }, 71 | { 72 | "pattern": "あの", 73 | "message": "指示語です。指示語を使うと文章が分かりにくくなります。具体的な表現を検討してください。", 74 | "tokens": [ 75 | { 76 | "tags0": "連体詞", 77 | "tags1": "*", 78 | "tags6": "あの" 79 | } 80 | ] 81 | }, 82 | { 83 | "pattern": "どの", 84 | "message": "指示語です。指示語を使うと文章が分かりにくくなります。具体的な表現を検討してください。", 85 | "tokens": [ 86 | { 87 | "tags0": "連体詞", 88 | "tags1": "*", 89 | "tags6": "どの" 90 | } 91 | ] 92 | }, 93 | { 94 | "pattern": "ここ", 95 | "message": "指示語です。指示語を使うと文章が分かりにくくなります。具体的な表現を検討してください。", 96 | "tokens": [ 97 | { 98 | "tags0": "名詞", 99 | "tags1": "代名詞", 100 | "tags6": "ここ" 101 | } 102 | ] 103 | }, 104 | { 105 | "pattern": "そこ", 106 | "message": "指示語です。指示語を使うと文章が分かりにくくなります。具体的な表現を検討してください。", 107 | "tokens": [ 108 | { 109 | "tags0": "名詞", 110 | "tags1": "代名詞", 111 | "tags6": "そこ" 112 | } 113 | ] 114 | }, 115 | { 116 | "pattern": "あそこ", 117 | "message": "指示語です。指示語を使うと文章が分かりにくくなります。具体的な表現を検討してください。", 118 | "tokens": [ 119 | { 120 | "tags0": "名詞", 121 | "tags1": "代名詞", 122 | "tags6": "あそこ" 123 | } 124 | ] 125 | }, 126 | { 127 | "pattern": "どこ", 128 | "message": "指示語です。指示語を使うと文章が分かりにくくなります。具体的な表現を検討してください。", 129 | "tokens": [ 130 | { 131 | "tags0": "名詞", 132 | "tags1": "代名詞", 133 | "tags6": "どこ" 134 | } 135 | ] 136 | }, 137 | { 138 | "pattern": "こちら", 139 | "message": "指示語です。指示語を使うと文章が分かりにくくなります。具体的な表現を検討してください。", 140 | "tokens": [ 141 | { 142 | "tags0": "名詞", 143 | "tags1": "代名詞", 144 | "tags6": "こちら" 145 | } 146 | ] 147 | }, 148 | { 149 | "pattern": "そちら", 150 | "message": "指示語です。指示語を使うと文章が分かりにくくなります。具体的な表現を検討してください。", 151 | "tokens": [ 152 | { 153 | "tags0": "名詞", 154 | "tags1": "代名詞", 155 | "tags6": "そちら" 156 | } 157 | ] 158 | }, 159 | { 160 | "pattern": "あちら", 161 | "message": "指示語です。指示語を使うと文章が分かりにくくなります。具体的な表現を検討してください。", 162 | "tokens": [ 163 | { 164 | "tags0": "名詞", 165 | "tags1": "代名詞", 166 | "tags6": "あちら" 167 | } 168 | ] 169 | }, 170 | { 171 | "pattern": "どちら", 172 | "message": "指示語です。指示語を使うと文章が分かりにくくなります。具体的な表現を検討してください。", 173 | "tokens": [ 174 | { 175 | "tags0": "名詞", 176 | "tags1": "代名詞", 177 | "tags6": "どちら" 178 | } 179 | ] 180 | } 181 | ]; 182 | 183 | var validateToken = function(sentence,terms){ 184 | 185 | var result = 0; 186 | var count = 0; 187 | for (var i = 0; i < sentence.tokens.length; i++) { 188 | for (var j = 0; j < terms.length; j++) { 189 | // 検査できる=今のTokenの位置+検査すべきTokenの数が検査すべきTokenの長さよりも小さい 190 | if ( i + terms[j].tokens.length - 1 < sentence.tokens.length ){ 191 | // 判定用変数を初期化 192 | // 規則にマッチしているかを一つずつチェック 193 | result = 0 194 | for (var k = 0; k < terms[j].tokens.length; k++){ 195 | if ( 196 | sentence.tokens[i+k].tags[0] === terms[j].tokens[k].tags0 && 197 | sentence.tokens[i+k].tags[1] === terms[j].tokens[k].tags1 && 198 | sentence.tokens[i+k].tags[6] === terms[j].tokens[k].tags6 199 | ){ 200 | result++; 201 | } 202 | } 203 | // チェックした結果が規則の個数と一致したら、こそあどとみなす 204 | if (result === terms[j].tokens.length){ 205 | count++; 206 | } 207 | } 208 | } 209 | } 210 | return count 211 | } 212 | 213 | var count = '' 214 | count = validateToken(sentence,terms); 215 | 216 | if ( count >= 2 ){ 217 | addError( "複数のこそあど言葉が使われています。", sentence); 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /use-joyo-Kanji.js: -------------------------------------------------------------------------------- 1 | function validateSentence(sentence) { 2 | // 参考 3 | // https://www.jtf.jp/jp/style_guide/pdf/jtf_style_guide.pdf 4 | // 2.1.2. 漢字 5 | // 漢字は「全角」で表記します。漢字の使用は、平成 22 年 11 月 30 日内閣告示第 2 号の「常用漢字表」に原則として準じます。 6 | 7 | // 参考 8 | // http://www.benricho.org/kanji/kyoikukanji/check-jyoyo-kanji.html 9 | // http://nanto.asablo.jp/blog/2015/12/31/7966713 10 | 11 | // http://www.benricho.org/kanji/kyoikukanji/check-jyoyo-kanji.html 12 | joyoKanji = ['亜','哀','挨','愛','曖','悪','握','圧','扱','宛','嵐','安','案','暗','以','衣','位','囲','医','依','委','威','為','畏','胃','尉','異','移','萎','偉','椅','彙','意','違','維','慰','遺','緯','域','育','一','壱','逸','茨','芋','引','印','因','咽','姻','員','院','淫','陰','飲','隠','韻','右','宇','羽','雨','唄','鬱','畝','浦','運','雲','永','泳','英','映','栄','営','詠','影','鋭','衛','易','疫','益','液','駅','悦','越','謁','閲','円','延','沿','炎','怨','宴','媛','援','園','煙','猿','遠','鉛','塩','演','縁','艶','汚','王','凹','央','応','往','押','旺','欧','殴','桜','翁','奥','横','岡','屋','億','憶','臆','虞','乙','俺','卸','音','恩','温','穏','下','化','火','加','可','仮','何','花','佳','価','果','河','苛','科','架','夏','家','荷','華','菓','貨','渦','過','嫁','暇','禍','靴','寡','歌','箇','稼','課','蚊','牙','瓦','我','画','芽','賀','雅','餓','介','回','灰','会','快','戒','改','怪','拐','悔','海','界','皆','械','絵','開','階','塊','楷','解','潰','壊','懐','諧','貝','外','劾','害','崖','涯','街','慨','蓋','該','概','骸','垣','柿','各','角','拡','革','格','核','殻','郭','覚','較','隔','閣','確','獲','嚇','穫','学','岳','楽','額','顎','掛','潟','括','活','喝','渇','割','葛','滑','褐','轄','且','株','釜','鎌','刈','干','刊','甘','汗','缶','完','肝','官','冠','巻','看','陥','乾','勘','患','貫','寒','喚','堪','換','敢','棺','款','間','閑','勧','寛','幹','感','漢','慣','管','関','歓','監','緩','憾','還','館','環','簡','観','韓','艦','鑑','丸','含','岸','岩','玩','眼','頑','顔','願','企','伎','危','机','気','岐','希','忌','汽','奇','祈','季','紀','軌','既','記','起','飢','鬼','帰','基','寄','規','亀','喜','幾','揮','期','棋','貴','棄','毀','旗','器','畿','輝','機','騎','技','宜','偽','欺','義','疑','儀','戯','擬','犠','議','菊','吉','喫','詰','却','客','脚','逆','虐','九','久','及','弓','丘','旧','休','吸','朽','臼','求','究','泣','急','級','糾','宮','救','球','給','嗅','窮','牛','去','巨','居','拒','拠','挙','虚','許','距','魚','御','漁','凶','共','叫','狂','京','享','供','協','況','峡','挟','狭','恐','恭','胸','脅','強','教','郷','境','橋','矯','鏡','競','響','驚','仰','暁','業','凝','曲','局','極','玉','巾','斤','均','近','金','菌','勤','琴','筋','僅','禁','緊','錦','謹','襟','吟','銀','区','句','苦','駆','具','惧','愚','空','偶','遇','隅','串','屈','掘','窟','熊','繰','君','訓','勲','薫','軍','郡','群','兄','刑','形','系','径','茎','係','型','契','計','恵','啓','掲','渓','経','蛍','敬','景','軽','傾','携','継','詣','慶','憬','稽','憩','警','鶏','芸','迎','鯨','隙','劇','撃','激','桁','欠','穴','血','決','結','傑','潔','月','犬','件','見','券','肩','建','研','県','倹','兼','剣','拳','軒','健','険','圏','堅','検','嫌','献','絹','遣','権','憲','賢','謙','鍵','繭','顕','験','懸','元','幻','玄','言','弦','限','原','現','舷','減','源','厳','己','戸','古','呼','固','股','虎','孤','弧','故','枯','個','庫','湖','雇','誇','鼓','錮','顧','五','互','午','呉','後','娯','悟','碁','語','誤','護','口','工','公','勾','孔','功','巧','広','甲','交','光','向','后','好','江','考','行','坑','孝','抗','攻','更','効','幸','拘','肯','侯','厚','恒','洪','皇','紅','荒','郊','香','候','校','耕','航','貢','降','高','康','控','梗','黄','喉','慌','港','硬','絞','項','溝','鉱','構','綱','酵','稿','興','衡','鋼','講','購','乞','号','合','拷','剛','傲','豪','克','告','谷','刻','国','黒','穀','酷','獄','骨','駒','込','頃','今','困','昆','恨','根','婚','混','痕','紺','魂','墾','懇','左','佐','沙','査','砂','唆','差','詐','鎖','座','挫','才','再','災','妻','采','砕','宰','栽','彩','採','済','祭','斎','細','菜','最','裁','債','催','塞','歳','載','際','埼','在','材','剤','財','罪','崎','作','削','昨','柵','索','策','酢','搾','錯','咲','冊','札','刷','刹','拶','殺','察','撮','擦','雑','皿','三','山','参','桟','蚕','惨','産','傘','散','算','酸','賛','残','斬','暫','士','子','支','止','氏','仕','史','司','四','市','矢','旨','死','糸','至','伺','志','私','使','刺','始','姉','枝','祉','肢','姿','思','指','施','師','恣','紙','脂','視','紫','詞','歯','嗣','試','詩','資','飼','誌','雌','摯','賜','諮','示','字','寺','次','耳','自','似','児','事','侍','治','持','時','滋','慈','辞','磁','餌','璽','鹿','式','識','軸','七','�','�','失','室','疾','執','湿','嫉','漆','質','実','芝','写','社','車','舎','者','射','捨','赦','斜','煮','遮','謝','邪','蛇','尺','借','酌','釈','爵','若','弱','寂','手','主','守','朱','取','狩','首','殊','珠','酒','腫','種','趣','寿','受','呪','授','需','儒','樹','収','囚','州','舟','秀','周','宗','拾','秋','臭','修','袖','終','羞','習','週','衆','集','愁','酬','醜','蹴','襲','十','汁','充','住','柔','重','従','渋','銃','獣','縦','叔','祝','宿','淑','粛','縮','塾','熟','出','述','術','俊','春','瞬','旬','巡','盾','准','殉','純','循','順','準','潤','遵','処','初','所','書','庶','暑','署','緒','諸','女','如','助','序','叙','徐','除','小','升','少','召','匠','床','抄','肖','尚','招','承','昇','松','沼','昭','宵','将','消','症','祥','称','笑','唱','商','渉','章','紹','訟','勝','掌','晶','焼','焦','硝','粧','詔','証','象','傷','奨','照','詳','彰','障','憧','衝','賞','償','礁','鐘','上','丈','冗','条','状','乗','城','浄','剰','常','情','場','畳','蒸','縄','壌','嬢','錠','譲','醸','色','拭','食','植','殖','飾','触','嘱','織','職','辱','尻','心','申','伸','臣','芯','身','辛','侵','信','津','神','唇','娠','振','浸','真','針','深','紳','進','森','診','寝','慎','新','審','震','薪','親','人','刃','仁','尽','迅','甚','陣','尋','腎','須','図','水','吹','垂','炊','帥','粋','衰','推','酔','遂','睡','穂','随','髄','枢','崇','数','据','杉','裾','寸','瀬','是','井','世','正','生','成','西','声','制','姓','征','性','青','斉','政','星','牲','省','凄','逝','清','盛','婿','晴','勢','聖','誠','精','製','誓','静','請','整','醒','税','夕','斥','石','赤','昔','析','席','脊','隻','惜','戚','責','跡','積','績','籍','切','折','拙','窃','接','設','雪','摂','節','説','舌','絶','千','川','仙','占','先','宣','専','泉','浅','洗','染','扇','栓','旋','船','戦','煎','羨','腺','詮','践','箋','銭','潜','線','遷','選','薦','繊','鮮','全','前','善','然','禅','漸','膳','繕','狙','阻','祖','租','素','措','粗','組','疎','訴','塑','遡','礎','双','壮','早','争','走','奏','相','荘','草','送','倉','捜','挿','桑','巣','掃','曹','曽','爽','窓','創','喪','痩','葬','装','僧','想','層','総','遭','槽','踪','操','燥','霜','騒','藻','造','像','増','憎','蔵','贈','臓','即','束','足','促','則','息','捉','速','側','測','俗','族','属','賊','続','卒','率','存','村','孫','尊','損','遜','他','多','汰','打','妥','唾','堕','惰','駄','太','対','体','耐','待','怠','胎','退','帯','泰','堆','袋','逮','替','貸','隊','滞','態','戴','大','代','台','第','題','滝','宅','択','沢','卓','拓','託','濯','諾','濁','但','達','脱','奪','棚','誰','丹','旦','担','単','炭','胆','探','淡','短','嘆','端','綻','誕','鍛','団','男','段','断','弾','暖','談','壇','地','池','知','値','恥','致','遅','痴','稚','置','緻','竹','畜','逐','蓄','築','秩','窒','茶','着','嫡','中','仲','虫','沖','宙','忠','抽','注','昼','柱','衷','酎','鋳','駐','著','貯','丁','弔','庁','兆','町','長','挑','帳','張','彫','眺','釣','頂','鳥','朝','貼','超','腸','跳','徴','嘲','潮','澄','調','聴','懲','直','勅','捗','沈','珍','朕','陳','賃','鎮','追','椎','墜','通','痛','塚','漬','坪','爪','鶴','低','呈','廷','弟','定','底','抵','邸','亭','貞','帝','訂','庭','逓','停','偵','堤','提','程','艇','締','諦','泥','的','笛','摘','滴','適','敵','溺','迭','哲','鉄','徹','撤','天','典','店','点','展','添','転','塡','田','伝','殿','電','斗','吐','妬','徒','途','都','渡','塗','賭','土','奴','努','度','怒','刀','冬','灯','当','投','豆','東','到','逃','倒','凍','唐','島','桃','討','透','党','悼','盗','陶','塔','搭','棟','湯','痘','登','答','等','筒','統','稲','踏','糖','頭','謄','藤','闘','騰','同','洞','胴','動','堂','童','道','働','銅','導','瞳','峠','匿','特','得','督','徳','篤','毒','独','読','栃','凸','突','届','屯','豚','頓','貪','鈍','曇','丼','那','奈','内','梨','謎','鍋','南','軟','難','二','尼','弐','匂','肉','虹','日','入','乳','尿','任','妊','忍','認','寧','熱','年','念','捻','粘','燃','悩','納','能','脳','農','濃','把','波','派','破','覇','馬','婆','罵','拝','杯','背','肺','俳','配','排','敗','廃','輩','売','倍','梅','培','陪','媒','買','賠','白','伯','拍','泊','迫','剝','舶','博','薄','麦','漠','縛','爆','箱','箸','畑','肌','八','鉢','発','髪','伐','抜','罰','閥','反','半','氾','犯','帆','汎','伴','判','坂','阪','板','版','班','畔','般','販','斑','飯','搬','煩','頒','範','繁','藩','晩','番','蛮','盤','比','皮','妃','否','批','彼','披','肥','非','卑','飛','疲','秘','被','悲','扉','費','碑','罷','避','尾','眉','美','備','微','鼻','膝','肘','匹','必','泌','筆','姫','百','氷','表','俵','票','評','漂','標','苗','秒','病','描','猫','品','浜','貧','賓','頻','敏','瓶','不','夫','父','付','布','扶','府','怖','阜','附','訃','負','赴','浮','婦','符','富','普','腐','敷','膚','賦','譜','侮','武','部','舞','封','風','伏','服','副','幅','復','福','腹','複','覆','払','沸','仏','物','粉','紛','雰','噴','墳','憤','奮','分','文','聞','丙','平','兵','併','並','柄','陛','閉','塀','幣','弊','蔽','餅','米','壁','璧','癖','別','蔑','片','辺','返','変','偏','遍','編','弁','便','勉','歩','保','哺','捕','補','舗','母','募','墓','慕','暮','簿','方','包','芳','邦','奉','宝','抱','放','法','泡','胞','俸','倣','峰','砲','崩','訪','報','蜂','豊','飽','褒','縫','亡','乏','忙','坊','妨','忘','防','房','肪','某','冒','剖','紡','望','傍','帽','棒','貿','貌','暴','膨','謀','頰','北','木','朴','牧','睦','僕','墨','撲','没','勃','堀','本','奔','翻','凡','盆','麻','摩','磨','魔','毎','妹','枚','昧','埋','幕','膜','枕','又','末','抹','万','満','慢','漫','未','味','魅','岬','密','蜜','脈','妙','民','眠','矛','務','無','夢','霧','娘','名','命','明','迷','冥','盟','銘','鳴','滅','免','面','綿','麺','茂','模','毛','妄','盲','耗','猛','網','目','黙','門','紋','問','冶','夜','野','弥','厄','役','約','訳','薬','躍','闇','由','油','喩','愉','諭','輸','癒','唯','友','有','勇','幽','悠','郵','湧','猶','裕','遊','雄','誘','憂','融','優','与','予','余','誉','預','幼','用','羊','妖','洋','要','容','庸','揚','揺','葉','陽','溶','腰','様','瘍','踊','窯','養','擁','謡','曜','抑','沃','浴','欲','翌','翼','拉','裸','羅','来','雷','頼','絡','落','酪','辣','乱','卵','覧','濫','藍','欄','吏','利','里','理','痢','裏','履','璃','離','陸','立','律','慄','略','柳','流','留','竜','粒','隆','硫','侶','旅','虜','慮','了','両','良','料','涼','猟','陵','量','僚','領','寮','療','瞭','糧','力','緑','林','厘','倫','輪','隣','臨','瑠','涙','累','塁','類','令','礼','冷','励','戻','例','鈴','零','霊','隷','齢','麗','暦','歴','列','劣','烈','裂','恋','連','廉','練','錬','呂','炉','賂','路','露','老','労','弄','郎','朗','浪','廊','楼','漏','籠','六','録','麓','論','和','話','賄','脇','惑','枠','湾','腕']; 13 | 14 | // http://nanto.asablo.jp/blog/2015/12/31/7966713 15 | var regex = new RegExp('(?:[\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u3005\u3007\u3021-\u3029\u3038-\u303B\u3400-\u4DB5\u4E00-\u9FCC\uF900-\uFA6D\uFA70-\uFAD9]|[\uD840-\uD868][\uDC00-\uDFFF]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|[\uD86A-\uD86C][\uDC00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D]|\uD87E[\uDC00-\uDE1D])','g'); 16 | // 文章中に漢字があるかどうかを正規表現で確認する 17 | var result = sentence.content.match(regex); 18 | // 漢字が格納されている配列内に、常用漢字があるかをチェックする 19 | if ( result !== null ) { 20 | for ( var k = 0; k < result.length; k++ ){ 21 | if ( joyoKanji.indexOf(result[k]) == -1 ) { 22 | addError('「' + result[k] + '」は常用漢字ではありません。常用漢字を利用してください', sentence); 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /use-hiragana-and-kanji-properly.js: -------------------------------------------------------------------------------- 1 | function validateSentence(sentence) { 2 | // 参考 3 | // https://www.jtf.jp/jp/style_guide/pdf/jtf_style_guide.pdf 4 | // 2.2.1. ひらがなと漢字の使い分け 5 | // 漢字は「全角」で表記します。漢字の使用は、平成 22 年 11 月 30 日内閣告示第 2 号の「常用漢字表」に原則として準じます。 6 | 7 | var terms = [ 8 | { 9 | 'expected':'あらかじめ', 10 | 'pattern':['予め'] 11 | }, 12 | { 'expected':'いずれ', 13 | 'pattern':['何れ'] 14 | }, 15 | { 16 | 'expected':'いつ', 17 | 'pattern':['何時'], 18 | 'tokenCheck':['名詞','代名詞','何時'] // この形で形態素解析される「何時」がすくない。何と時にTokenizeされる。。。 19 | }, 20 | { 'expected':'おおよそ', 21 | 'pattern':['凡そ'] 22 | }, 23 | { 'expected':'かえって', 24 | 'pattern':['却って'], 25 | 'tokenCheck':['副詞','一般','却って'] 26 | }, 27 | { 'expected':'かつ', 28 | 'pattern':['且つ'] 29 | }, 30 | { 'expected':'かもしれない', 31 | 'pattern':['かも知れない'] 32 | }, 33 | { 34 | 'expected':'ください', 35 | 'pattern':['下さい'], 36 | 'tokenCheck':['動詞','非自立','下さる'] 37 | }, 38 | { 'expected':'これほど', 39 | 'pattern':['これ程'] 40 | }, 41 | { 'expected':'ご', 42 | 'pattern':['御'], 43 | 'tokenCheck':['接頭詞','名詞接続','御'] 44 | }, 45 | { 'expected':'子ども', 46 | 'pattern':['こども|子供'] 47 | }, 48 | { 49 | 'expected':'さらに', 50 | 'pattern':['更に'], 51 | 'tokenCheck':['副詞','助詞類接続','更に'] 52 | }, 53 | { 54 | 'expected':'しかし', 55 | 'pattern':['然し'] 56 | }, 57 | { 58 | 'expected':'しばらく', 59 | 'pattern':['暫く'] 60 | }, 61 | { 62 | 'expected':'すなわち', 63 | 'pattern':['即ち'] 64 | }, 65 | /* スタイルガイドにはあるが、実際に使うことはないと思うので削除 66 | { 67 | 'expected':'すべき', 68 | 'pattern':['可き'], 69 | }, 70 | */ 71 | { 72 | 'expected':'せっかく', 73 | 'pattern':['折角'] 74 | }, 75 | { 76 | 'expected':'たびたび', 77 | 'pattern':['度々'] 78 | }, 79 | { 80 | 'expected':'ただし', 81 | 'pattern':['但し'], 82 | 'tokenCheck':['接続詞','*','但し'] 83 | }, 84 | { 85 | 'expected':'たち', 86 | 'pattern':['達'], 87 | 'tokenCheck':['名詞','接尾','達'] //中々検知しないので、個別に下で定義。。。 88 | }, 89 | { 90 | 'expected':'人たち', 91 | 'pattern':['人達'], 92 | 'tokenCheck':['名詞','一般','人達'] 93 | }, 94 | { 95 | 'expected':'できる', 96 | 'pattern':['出来る'], 97 | 'tokenCheck':['動詞','自立','出来る'] 98 | }, 99 | { 100 | 'expected':'どこ', 101 | 'pattern':['何処'] 102 | }, 103 | { 104 | 'expected':'ないし', 105 | 'pattern':['乃至'] 106 | }, 107 | { 108 | 'expected':'なお', 109 | 'pattern':['尚'], 110 | 'tokenCheck':['接続詞','*','尚'] 111 | }, 112 | { 113 | 'expected':'なかなか', //少々精度に不安あり 114 | 'pattern':['中々'] 115 | }, 116 | /*いい感じの形態素解析が思いつかないのでパス 117 | { 118 | 'expected':'ほど', 119 | 'pattern':['程'], 120 | }, 121 | */ 122 | { 123 | 'expected':'または', 124 | 'pattern':['又は'], 125 | 'tokenCheck':['接続詞','*','又は'] 126 | }, 127 | { 128 | 'expected':'むしろ', 129 | 'pattern':['寧ろ'] 130 | }, 131 | { 132 | 'expected':'めったに', 133 | 'pattern':['滅多に'] 134 | }, 135 | { 136 | 'expected':'もはや', 137 | 'pattern':['最早'] 138 | }, 139 | { 140 | 'expected':'もしくは', 141 | 'pattern':['若しくは'] 142 | }, 143 | { 144 | 'expected':'もって', 145 | 'pattern':['以て|以って'] 146 | }, 147 | { 148 | 'expected':'ように', 149 | 'pattern':['様に'], 150 | 'tokenCheck':['名詞','非自立','様'] 151 | }, 152 | { 153 | 'expected':'よほど', 154 | 'pattern':['余程'] 155 | }, 156 | // JTF-2.2.1 漢字で書く 157 | { 158 | 'expected':'一切', 159 | 'pattern':['いっさい'] 160 | }, 161 | { 162 | 'expected':'必ず', 163 | 'pattern':['かならず'] 164 | }, 165 | { 166 | 'expected':'大いに', 167 | 'pattern':['おおいに'] 168 | }, 169 | { 170 | 'expected':'強いて', 171 | 'pattern':['しいて'], 172 | 'tokenCheck':['副詞','一般','しいて'] 173 | }, 174 | /* いい感じの検知方法が見当たらないのでパス 175 | { 176 | 'expected':'中', 177 | 'pattern':['じゅう'], 178 | }, 179 | */ 180 | { 181 | 'expected':'時々', 182 | 'pattern':['ときどき'], 183 | 'tokenCheck':['副詞','一般','ときどき'] 184 | }, 185 | { 186 | 'expected':'何しろ', 187 | 'pattern':['なにしろ'], 188 | 'tokenCheck':['副詞','一般','なにしろ'] 189 | }, 190 | /* いい感じの検知方法が見当たらないのでパス 191 | { 192 | 'expected':'何も', 193 | 'pattern':['なにも'], 194 | }, 195 | */ 196 | { 197 | 'expected':'何らかの', 198 | 'pattern':['なんらかの'], 199 | 'tokenCheck':['連体詞','*','なんらかの'] 200 | }, 201 | { 202 | 'expected':'何とも', 203 | 'pattern':['なんとも'], 204 | 'tokenCheck':['副詞','一般','なんとも'] 205 | }, 206 | // JTF-2.2.1 漢字を使い分ける 207 | { 208 | 'expected':'箇所', 209 | 'pattern':['個所'] 210 | }, 211 | { 212 | 'expected':'箇条書き', 213 | 'pattern':['個条書き'] 214 | }, 215 | /* いい感じの検知方法が見当たらないのでパス 216 | { 217 | 'expected':'付属する', 218 | 'pattern':['附属する'], 219 | }, 220 | */ 221 | { 222 | 'expected':'摩耗', 223 | 'pattern':['磨耗'] 224 | }, 225 | { 226 | 'expected':'摩滅', 227 | 'pattern':['磨滅'] 228 | }, 229 | // JTF=2.2.1 品詞・意味で使い分ける 230 | { 231 | 'expected':'および', 232 | 'pattern':['及び'], 233 | 'tokenCheck':['接続詞','*','及び'] 234 | }, 235 | { 236 | 'expected':'及ぶ', 237 | 'pattern':['およぶ'], 238 | 'tokenCheck':['動詞','自立','およぶ'] 239 | }, 240 | { 241 | 'expected':'いたします', 242 | 'pattern':['致します'], 243 | 'tokenCheck':['動詞','非自立','致す'] 244 | }, 245 | { 246 | 'expected':'致す', 247 | 'pattern':['いたす'], 248 | 'tokenCheck':['動詞','自立','いたす'] 249 | }, 250 | { 251 | 'expected':'したがって', 252 | 'pattern':['従って'], 253 | 'tokenCheck':['接続詞','*','従って'] 254 | }, 255 | { 256 | 'expected':'従う', 257 | 'pattern':['したがう'], 258 | 'tokenCheck':['動詞','自立','したがう'] 259 | }, 260 | /* これは形態素解析でも無理だと思う。。。 261 | { 262 | 'expected':'出す', 263 | 'pattern':['だす'], 264 | }, 265 | { 266 | 'expected':'だす', 267 | 'pattern':['出す'], 268 | }, 269 | */ 270 | { 271 | 'expected':'付く', 272 | 'pattern':['つく'], 273 | 'tokenCheck':['動詞','自立','つく'] 274 | }, 275 | /* 活気付くや凍り付くが、一つの単語でTokenizeされてしまうため、検知できない。 276 | { 277 | 'expected':'つき', 278 | 'pattern':['付き'], 279 | 'tokenCheck':['名詞','接尾','付き'] //手付きや目付きは一つの名詞になってしまうので検知できない。。。 280 | // 好み 281 | }, 282 | { 283 | 'expected':'とおり', 284 | 'pattern':['通り'], 285 | 'tokenCheck':['名詞','非自立','通り'] //「以下の通り」の通りは「名詞・一般」になってしまう。これを対象にしてしまうと、道路を意味する「通り」が平仮名になってしまう。。。 286 | }, 287 | */ 288 | { 289 | 'expected':'以下のとおり', 290 | 'pattern':['以下の通り'] // とりあえずこれは検知したいので個別に。 291 | }, 292 | { 293 | 'expected':'通り', 294 | 'pattern':['とおり'], 295 | 'tokenCheck':['名詞','接尾','とおり'] 296 | }, 297 | { 298 | 'expected':'ほしい', 299 | 'pattern':['欲しい'], 300 | 'tokenCheck':['形容詞','非自立','欲しい'] 301 | }, 302 | { 303 | 'expected':'欲しい', 304 | 'pattern':['ほしい'], 305 | 'tokenCheck':['形容詞','自立','ほしい'] 306 | }, 307 | // JTF=2.2.1 複数の表記方法が一般的で、実務文書で頻出する語 308 | { 309 | 'expected':'あまりに', 310 | 'pattern':['余りに'] 311 | }, 312 | { 313 | 'expected':'きわめて', 314 | 'pattern':['極めて'] 315 | }, 316 | { 317 | 'expected':'さまざま', 318 | 'pattern':['様々'] 319 | }, 320 | { 321 | 'expected':'すでに', 322 | 'pattern':['既に'] 323 | }, 324 | { 325 | 'expected':'すべて', 326 | 'pattern':['全て'] 327 | }, 328 | { 329 | 'expected':'ともに', 330 | 'pattern':['共に'], 331 | 'tokenCheck':['副詞','一般','共に'] 332 | }, 333 | { 334 | 'expected':'たとえば', 335 | 'pattern':['例えば'] 336 | }, 337 | { 338 | 'expected':'ただちに', 339 | 'pattern':['直ちに'] 340 | }, 341 | { 342 | 'expected':'とうてい', 343 | 'pattern':['到底'] 344 | }, 345 | { 346 | 'expected':'はたして', 347 | 'pattern':['果たして'] 348 | }, 349 | { 350 | 'expected':'ひときわ', 351 | 'pattern':['一際'] 352 | }, 353 | /* kuromojiのテストツールが、「一度」を「ひとたび」と認識しないので対応できない 354 | { 355 | 'expected':'ひとたび', 356 | 'pattern':['一度'], 357 | }, 358 | */ 359 | { 360 | 'expected':'ほか', 361 | 'pattern':['他'], 362 | 'tokenCheck':['名詞','一般','他'] // 他を探す 363 | }, 364 | { 365 | 'expected':'ほか', 366 | 'pattern':['他'], 367 | 'tokenCheck':['名詞','非自立','他'] // この他に必要なもの 368 | }, 369 | { 370 | 'expected':'ほか', 371 | 'pattern':['外'], 372 | 'tokenCheck':['名詞','副詞可能','外'] // 思いの外が他でTokenizeされない。。。 373 | }, 374 | { 375 | 'expected':'思いのほか', 376 | 'pattern':['思いの外'] 377 | }, 378 | { 379 | 'expected':'ほかならぬ', 380 | 'pattern':['他ならぬ|外ならぬ'] 381 | }, 382 | { 383 | 'expected':'まったく', 384 | 'pattern':['全く'] 385 | }, 386 | { 387 | 'expected':'もともと', 388 | 'pattern':['元々'] 389 | }, 390 | { 391 | 'expected':'わかる', 392 | 'pattern':['分かる'], 393 | 'tokenCheck':['動詞','自立','分かる'] 394 | }, 395 | { 396 | 'expected':'わかる', 397 | 'pattern':['解る'], 398 | 'tokenCheck':['動詞','自立','解る'] 399 | }, 400 | { 401 | 'expected':'わかる', 402 | 'pattern':['判る'], 403 | 'tokenCheck':['動詞','自立','判る'] 404 | }, 405 | { 406 | 'expected':'ひとつひとつ', 407 | 'pattern':['一つ一つ'] 408 | }, 409 | { 410 | 'expected':'わたし', 411 | 'pattern':['私'], 412 | 'tokenCheck':['名詞','代名詞','私'] 413 | }, 414 | { 415 | 'expected':'われわれ', 416 | 'pattern':['我々'], 417 | 'tokenCheck':['名詞','代名詞','我々'] 418 | }, 419 | // 過剰検知しそう。適宜形態素解析に切り替える 420 | { 421 | 'expected':'わが', 422 | 'pattern':['我が'] 423 | } 424 | ]; 425 | 426 | var tokenCheck = function (sentence){ 427 | for (var k = 0; k < sentence.tokens.length; k++) { 428 | // 2.2.1 429 | if ( sentence.tokens[k].tags[0] === terms[i]['tokenCheck'][0] && 430 | sentence.tokens[k].tags[1] === terms[i]['tokenCheck'][1] && 431 | sentence.tokens[k].tags[6].match(new RegExp(terms[i]['tokenCheck'][2])) ){ 432 | addError(' 「' + sentence.tokens[k].surface + '」を「' + terms[i]['expected'] + '」に修正してください' , sentence); 433 | } 434 | } 435 | } 436 | 437 | for ( var i = 0; i < terms.length; i++ ) { 438 | for ( var j = 0; j < terms[i]['pattern'].length; j++ ) { 439 | var regex = new RegExp( terms[i]['pattern'][j]); 440 | // 形態素解析するかどうか 441 | if ( 'tokenCheck' in terms[i] ) { 442 | tokenCheck(sentence); 443 | } else { 444 | if ( sentence.content.match(regex) ) { 445 | addError('「' + terms[i]['pattern'][j] + '」を「' + terms[i]['expected'] + '」に修正してください', sentence); 446 | } 447 | } 448 | } 449 | } 450 | } 451 | --------------------------------------------------------------------------------