├── .gitignore ├── package.json ├── test.js ├── mecab.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | node_modules 15 | npm-debug.log 16 | package-lock.json 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mecab-async", 3 | "version": "0.1.2", 4 | "author": { 5 | "name": "hecomi", 6 | "email": "info@hecomi.com" 7 | }, 8 | "main": "mecab", 9 | "dependencies": { 10 | "shell-quote": "*" 11 | }, 12 | "readmeFilename": "README.md", 13 | "description": "Asynchronous japanese morphological analyzer using MeCab.", 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/hecomi/node-mecab-async.git" 17 | }, 18 | "bugs": { 19 | "mail": "info@hecomi.com", 20 | "url": "http://github.com/hecomi/node-mecab-async/issues" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | var MeCab = new require('./mecab.js'); 2 | MeCab.command = 'mecab -E "<改行>\\n"'; // 例えばEOSを <改行> と表示する 3 | MeCab.options = { 4 | maxBuffer: 300 * 1024, 5 | timeout: 1000 6 | }; 7 | 8 | runAllFeatures('すもももももももものうち'); 9 | 10 | runPartialFeature('\'"\\'); 11 | runPartialFeature('&\necho abc'); 12 | runPartialFeature('abc | cat'); 13 | 14 | function runAllFeatures(testWord) { 15 | // 非同期版 16 | MeCab.parse(testWord, function (err, result) { 17 | if (err) throw err; 18 | console.log('非同期:\n', result); 19 | }); 20 | 21 | // 非同期版 22 | MeCab.wakachi(testWord, function (err, result) { 23 | if (err) throw err; 24 | console.log('非同期(わかち書き):\n', result); 25 | }); 26 | 27 | // 非同期版 28 | MeCab.parseFormat(testWord, function (err, result) { 29 | if (err) throw err; 30 | console.log('非同期(フォーマット整形):\n', result); 31 | }); 32 | 33 | // 同期版 34 | console.log('同期:\n', MeCab.parseSync(testWord)); 35 | 36 | // 同期版 37 | console.log('同期(わかち書き):\n', MeCab.wakachiSync(testWord)); 38 | 39 | // 同期版 40 | console.log('同期(フォーマット整形):\n', MeCab.parseSyncFormat(testWord)); 41 | } 42 | 43 | function runPartialFeature(testWord) { 44 | console.log("わかち書き " + testWord + " :\n", MeCab.wakachiSync(testWord)); 45 | } 46 | -------------------------------------------------------------------------------- /mecab.js: -------------------------------------------------------------------------------- 1 | const exec = require('child_process').exec; 2 | const execSync = require('child_process').execSync; 3 | const sq = require('shell-quote'); 4 | 5 | // for backward compatibility 6 | var MeCab = function() {}; 7 | 8 | MeCab.prototype = { 9 | command : 'mecab', 10 | options : {}, 11 | parser: data => (data.length <= 8) ? null : { 12 | // Ref: http://mecab.googlecode.com/svn/trunk/mecab/doc/index.html 13 | // 表層形\t品詞,品詞細分類1,品詞細分類2,品詞細分類3,活用形,活用型,原形,読み,発音 14 | kanji : data[0], 15 | lexical : data[1], 16 | compound : data[2], 17 | compound2 : data[3], 18 | compound3 : data[4], 19 | conjugation : data[5], 20 | inflection : data[6], 21 | original : data[7], 22 | reading : data[8], 23 | pronunciation : data[9] || '' 24 | }, 25 | _format : function(arr) { 26 | const results = []; 27 | if (!arr) { return results; } 28 | arr.forEach(data => { 29 | var result = this.parser(data); 30 | if (result) { results.push(result); } 31 | }); 32 | return results; 33 | }, 34 | _shellCommand : function(str) { 35 | return sq.quote(['echo', str]) + ' | ' + this.command; 36 | }, 37 | _parseMeCabResult : function(result) { 38 | return result.split('\n').map(line => { 39 | const arr = line.split('\t'); 40 | // EOS 41 | if (arr.length === 1) { 42 | return [line]; 43 | } 44 | return [arr[0]].concat(arr[1].split(',')); 45 | }); 46 | }, 47 | parse : function(str, callback) { 48 | process.nextTick(() => { // for bug 49 | exec(this._shellCommand(str), this.options, (err, result) => { 50 | if (err) { return callback(err); } 51 | callback(err, this._parseMeCabResult(result).slice(0, -2)); 52 | }); 53 | }); 54 | }, 55 | parseSync : function(str) { 56 | const result = execSync(this._shellCommand(str), this.options); 57 | return this._parseMeCabResult(String(result)).slice(0, -2); 58 | }, 59 | parseFormat : function(str, callback) { 60 | this.parse(str, (err, result) => { 61 | if (err) { return callback(err); } 62 | callback(err, this._format(result)); 63 | }); 64 | }, 65 | parseSyncFormat : function(str) { 66 | return this._format(this.parseSync(str)); 67 | }, 68 | _wakatsu : function(arr) { 69 | return arr.map(data => data[0]); 70 | }, 71 | wakachi : function(str, callback) { 72 | this.parse(str, (err, arr) => { 73 | if (err) { return callback(err); } 74 | callback(null, this._wakatsu(arr)); 75 | }); 76 | }, 77 | wakachiSync : function(str) { 78 | const arr = this.parseSync(str); 79 | return this._wakatsu(arr); 80 | } 81 | }; 82 | 83 | for (const x in MeCab.prototype) { 84 | MeCab[x] = MeCab.prototype[x]; 85 | } 86 | 87 | module.exports = MeCab; 88 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Asynchronous japanese morphological analyser using MeCab 2 | ============= 3 | 4 | これは何? 5 | -------------- 6 | 非同期で MeCab で結果をパースする Node.js 用モジュールです。 7 | 8 | インストール 9 | -------------- 10 | $ npm install mecab-async 11 | 12 | 使い方 13 | -------------- 14 | 以下のようにコールバック経由で解析結果を取得します。 15 | 16 | ```javascript 17 | var MeCab = new require('mecab-async') 18 | , mecab = new MeCab() 19 | ; 20 | mecab.parse('いつもニコニコあなたの隣に這い寄る混沌ニャルラトホテプです!', function(err, result) { 21 | if (err) throw err; 22 | console.log(result); 23 | }); 24 | ``` 25 | 26 | 結果: 27 | 28 | [ [ 'いつも', '副詞', '一般', '*', '*', '*', '*', 'いつも', 'イツモ', 'イツモ' ], 29 | [ 'ニコニコ', '副詞', '助詞類接続', '*', '*', '*', '*', 'ニコニコ', 'ニコニコ', 'ニコニコ' ], 30 | [ 'あなた', '名詞', '代名詞', '一般', '*', '*', '*', 'あなた', 'アナタ', 'アナタ' ], 31 | [ 'の', '助詞', '連体化', '*', '*', '*', '*', 'の', 'ノ', 'ノ' ], 32 | [ '隣', '名詞', '一般', '*', '*', '*', '*', '隣', 'トナリ', 'トナリ' ], 33 | [ 'に', '助詞', '格助詞', '一般', '*', '*', '*', 'に', 'ニ', 'ニ' ], 34 | [ '這い', '動詞', '自立', '*', '*', '五段・ワ行促音便', '連用形', '這う', 'ハイ', 'ハイ' ], 35 | [ '寄る', '動詞', '自立', '*', '*', '五段・ラ行', '基本形', '寄る', 'ヨル', 'ヨル' ], 36 | [ '混沌', '名詞', '一般', '*', '*', '*', '*', '混沌', 'コントン', 'コントン' ], 37 | [ 'ニャルラトホテプ', '名詞', '一般', '*', '*', '*', '*', '*' ], 38 | [ 'です', '助動詞', '*', '*', '*', '特殊・デス', '基本形', 'です', 'デス', 'デス' ], 39 | [ '!', '記号', '一般', '*', '*', '*', '*', '!', '!', '!' ] ] 40 | 41 | わかち書きもできます。 42 | 43 | ```javascript 44 | var MeCab = new require('mecab-async') 45 | , mecab = new MeCab() 46 | ; 47 | mecab.wakachi('いつもニコニコあなたの隣に這い寄る混沌ニャルラトホテプです!', function(err, result) { 48 | if (err) throw err; 49 | console.log(result); 50 | }); 51 | ``` 52 | 53 | 結果: 54 | 55 | [ 'いつも', 56 | 'ニコニコ', 57 | 'あなた', 58 | 'の', 59 | '隣', 60 | 'に', 61 | '這い', 62 | '寄る', 63 | '混沌', 64 | 'ニャルラトホテプ', 65 | 'です', 66 | '!' ] 67 | 68 | 同期版として `parseSync` および `wakachiSync` を使用することもできます。 69 | 70 | その他 71 | -------------- 72 | 73 | ### コマンドの変更 74 | 実行される `mecab` コマンドのパスを明示的に指定したかったり、より詳細なオプションを指定したかったりする場合、 75 | シェルコマンドをカスタマイズして使うこともできます。 76 | 77 | ```javascript 78 | var MeCab = new require('mecab-async') 79 | , mecab = new MeCab() 80 | ; 81 | mecab.command = '/usr/local/bin/mecab -E "<改行>\\n"'; // EOSを <改行> と表示 82 | ``` 83 | 84 | ### オプション 85 | `exec` コマンドの与えるオプションを以下のように指定できます。 86 | 87 | ```javascript 88 | var MeCab = new require('mecab-async') 89 | , mecab = new MeCab() 90 | ; 91 | mecab.options = { 92 | maxBuffer: 300 * 1024, 93 | timeout: 1000 94 | }; 95 | ``` 96 | 97 | ### パーサ 98 | 辞書によって結果が異なる場合は`parseFormat`および`parseSyncFormat`で使用されるパーサをカスタマイズできます。 99 | 100 | ```javascript 101 | var MeCab = new require('mecab-async') 102 | , mecab = new MeCab() 103 | ; 104 | mecab.parser = data => { 105 | kanji : data[0], 106 | lexical : data[1], 107 | compound : data[2], 108 | compound2 : data[3], 109 | compound3 : data[4], 110 | conjugation : data[5], 111 | inflection : data[6], 112 | original : data[7], 113 | reading : data[8], 114 | pronunciation : data[9] || '' 115 | }; 116 | ``` 117 | 118 | ライセンス 119 | ---------- 120 | The MIT License (MIT) 121 | 122 | Copyright (c) 2017 hecomi 123 | 124 | Permission is hereby granted, free of charge, to any person obtaining a copy of 125 | this software and associated documentation files (the "Software"), to deal in 126 | the Software without restriction, including without limitation the rights to 127 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 128 | the Software, and to permit persons to whom the Software is furnished to do so, 129 | subject to the following conditions: 130 | 131 | The above copyright notice and this permission notice shall be included in all 132 | copies or substantial portions of the Software. 133 | 134 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 135 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 136 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 137 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 138 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 139 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 140 | --------------------------------------------------------------------------------