Kuromoji.jsで形態素分析して文章の中から名詞だけ取り出してみた

こんばんは、Node.js/TypeScriptの環境でtakuyaa/kuromoji.jsを使って簡単に形態素分析ができたのでメモします。

yarn add kuromoji @types/kuromoji

使い方はこんな感じ

import kuromoji from 'kuromoji';

const tokenizer: kuromoji.Tokenizer<kuromoji.IpadicFeatures> = await new Promise((resolve, reject) => {
    kuromoji
      .builder({
        dicPath: './node_modules/kuromoji/dict',
      })
      .build((err, _tokenizer) => {
        if (!!err) {
          reject(err);
        }
        resolve(_tokenizer);
      });
  });


export const tokenize = (text: string) => {
  return tokenize(text)
}

本来やりたかったことは、文章から名詞だけを抽出したかったのですが、例えばキムチチャーハンという名詞を抽出したくても、とても細かい単位で分かち書きされるのでキムチチャーハンに分割されてしまいます。こうならないよう連続する名詞を結合して取得してみました

type ProperNoun = {
  position: number;
  word: string;
};

/**
 * 名詞を抽出する
 * NOTE: 連続する名詞を束ねてそれらのみにフィルタリングする
 */ 
export const extractProperNounList(text: string) {
  const pnList: ProperNoun[] = [];
  let consecutiveWord: ProperNoun | null = null;

  tokenize(text).forEach((result, i) => {
    if (result.pos !== '名詞') {
      if (consecutiveWord === null) return;
      pnList.push(consecutiveWord);
      consecutiveWord = null;
      return
    }


    if (consecutiveWord === null) {
      consecutiveWord = { word: '', position: result.word_position - 1 };
    }
    consecutiveWord.word = consecutiveWord.word + result.surface_form;
  });

  return pnList;
}

例えば僕の名前は田中太郎です。皆さんよろしくお願いいたします!好きな食べ物はキムチチャーハンと寿司ですね!という文章を投げると結果はこんな感じです、いい感じですね 🥰

[
  { word: '僕', position: 0 },
  { word: '名前', position: 2 },
  { word: '田中太郎', position: 5 },
  { word: '皆さん', position: 12 },
  { word: 'お願い', position: 19 },
  { word: '好き', position: 28 },
  { word: '食べ物', position: 31 },
  { word: 'キムチチャーハン', position: 35 },
  { word: '寿司', position: 44 }
]

See also