読者です 読者をやめる 読者になる 読者になる

コネヒト開発者ブログ

コネヒト開発者ブログ

Slackで簡単チェック!textlint で始める文字校正Bot

f:id:fortkle:20170216212251p:plain

こんにちは! 新オフィスに移転してから毎日2缶ドクターペッパーを買うのが習慣化してきた @fortkle です。

今回はSlackで簡単に文字校正ができるBotを作ってみたのでご紹介したいと思います。

手軽に校正したい

メールやチャットだけでなく、こういったブログやissueに書く仕様など「文章を書く」シーンはたくさんあると思います。

そんなとき自分が伝えたいことを相手にちゃんと伝えることができれば良いのですが、良い文章を書くのはなかなか難しく、今も試行錯誤しています。

そこで、相手に伝えたいことがちゃんと伝わる良い文章を書くためにSlack上で簡単に試せる文字校正Botを作ってみました。

成果物

実際に見たほうが早いと思うので画像を交えてご紹介します。 ちなみに ソースコードはGithubにあげている ので参考にしてみてください。

例として以下の文章をチェックしてみたいと思います。

この文章はご存知の通り、ダミーテキストです ヽ(^o^)丿
そして、様々な、エラーチェックに、引っかかる文章になっています。そして、意味はありません。
この文章が書くのが自動ではなく手動なのが地味に大変だったところです。
いや、大変だったとはいえないこともないです。このBOTはナウでヤングなやり方で
文章をチェックすることができます。チェック結果はslackで即座に見れます。
焦ってしまうとと誤字をすることがありますよね。そんなときに便利です。

チェックするにはSlackで文字校正Botに「check」から始まるDMを送るだけです。

check
ここにチェック
したい文章を
書きます。

実際に校正した結果がこちらです。

f:id:fortkle:20170216183734g:plain

1行目:ご存知 => 用字(ご存じ)
1行目:(^o^) => 顔文字が使われています。
2行目:様々 => 用字(さまざま)
2行目:エラーチェック => 半角カタカナが使われています。
2行目:同じ接続詞が連続して使われています。
3行目:一文に二回以上利用されている助詞 "が" がみつかりました。
4行目:こともない => 二重否定()
4行目:ナウ => 死語が使われています。
4行目:ヤング => 死語が使われています。
4行目:一文に二回以上利用されている助詞 "で" がみつかりました。
5行目:することができます => 冗長表現(できます)
5行目:見れ => ら抜き(見られ)
5行目:slack => 全角英数字が使われています。
6行目:"と" が連続して2回使われています。

どうでしょうか?意外と使えそうな気がしませんか! プロが使うような有料の校正ツールに比べると指摘内容は少ないですが、このように簡単に文字校正を試すことができます。

文字校正Botのメリット

誰でも簡単に使える!

まだ個人でしか使っていませんがもし会社で使うとなった場合でも、有償の文字校正ツールと違いSlackさえあれば誰でも利用できる手軽さがあります。 また、校正したいテキストをBotにDMで投げる形なのでチャンネルを汚すことなく利用できます。

自分が用意した辞書でカスタマイズできる!

実際の校正結果の画像をよく見ていただくと分かると思いますが、「顔文字」や「死語」などの指摘があるかと思います。 これらはどちらも自分で用意したオリジナルのルールです(死語はジョークルールですよ!)。 後述する prh というツールを使うと自分が用意した辞書を使って文章を校正することが出来ます。

校正内容のメンテナンスに夢が広がる!

今回は未実装ですが、実装さえすれば文字校正をするだけでなく校正内容も管理できると思います。

たとえば ng-word add [追加したい文言]ng-word remove [削除したい文言] などCRUD操作をできるようにしておけば Slack上から簡単に、しかも非エンジニアだけで校正内容をメンテナンスすることができそうですね!

仕組みの解説

今回の文字校正Botは Botkit をベースに textlintというツールを使ってSlack上での校正を実現しています。 Botkitのセットアップが終わりBotが動いている状態からスタートし、実際に文字校正ができるようになるところまでの実装手順をご紹介します。

1. 使っているツール

textlint

textlintは、@azu さんが作っている自然言語をLintできるツールです。JavaScriptにおけるESLintのように、あらかじめ設定しておいたルールに基づいて、テキスト上の間違いや読みにくい点などを指摘してくれます。

プラガブルであることが特徴でデフォルトでは1つもルールがありません。そのため、一般公開されているルールや自分で作ったルールを組み合わせる必要があります。

一般公開されているルールは こちら(Collection of textlint rule) で確認できます。 今回は校正のルールとして下記6つを採用しました。

採用ルール

2. インストール

textlint本体とルールをnpm経由でインストールしましょう。ここではyarnを使ってインストールします。

$ yarn add textlint textlint-rule-ja-yahoo-kousei textlint-rule-prh textlint-rule-no-doubled-conjunctive-particle-ga textlint-rule-no-doubled-conjunction textlint-rule-no-doubled-joshi textlint-rule-ja-no-successive-word

3. prh で使う辞書の作成

辞書はyaml形式で下記のように書くことができます(基本的な書き方はこちら を参考にしてください)。

version: 1
rules:
  # 大文字小文字全角半角の統一
  - expected: Cookie
  # 以下と等価 正規表現には強制でgフラグが付く
  # - expected: Cookie
  #   pattern: "/[CcCc][OoOo][OoOo][KkKk][IiIi][EeEe]/g"

  # 表現の統一を図る
  - expected: デフォルト
    patterns:  ディフォルト

さて、この設定ファイルを見ると分かる通り本来prhは表記ゆれを検出するためのツールですが、「独自の辞書を作れること」「エラーメッセージを辞書毎に設定できること」の2点から今回は簡易的なNGワードチェックのために使ってみることにします。本来の用途とは異なりますが、 expected に「エラーメッセージ」を書き、 patternにエラーにしたい単語を列挙します。

version: 1 
rules: 
  # 本来、expectedには「期待される値」が書かれるべきだがtextlint-rule-prhがprhフィールドに対応していないので「エラーメッセージ」を書く 
  - expected: 死語が使われています。 
    patterns: 
      - アイアム・ソーリー、ひげそーりー
      - あたりまえだのクラッカー 
      - アベック 
      - いただきマンモス 
      - うれピー 
      - おいくら万円 
      - オッケー牧場
      - ナウ
      - ヤング
      # (略)

4. textlint の設定ファイルを作成 ( .textlintrc )

次にtextlint の設定ファイルをJSON形式で作成し、 .textlintrc という名前で保存します。 .textlintrc には読み込みたいルールと設定を記述します。

{ 
  "rules" : { 
    "no-doubled-conjunctive-particle-ga": true,
    "no-doubled-conjunction": true,
    "no-doubled-joshi": true,
    "ja-no-successive-word": true,
    "ja-yahoo-kousei": true,
    "prh": {
      "rulePaths": [
        "./dict/prh.yml"  ← ここでprhで使う辞書を読み込む
      ] 
    } 
  }
}

ja-yahoo-kouseiルールを利用するためには事前にYahoo アプリケーションIDを取得する必要があります。 詳しくはREADMEを見てみてください。

5. textlintをモジュールとして使う

公式のドキュメントを参考に実装します。 実装例としてサンプルコードを載せておきます。

import path from 'path'
import {TextLintEngine} from 'textlint'

export default function(controller) {

  const engine = new TextLintEngine({
    configFile: path.join(__dirname, '../.textlintrc'),
  })

  const formatResults = (results) => {
    let output = '```\n'
    const messages = results[0].messages
    for (let i = 0; i < messages.length; i++) {
      const msg = messages[i]
      const msgText = `${msg.line}行目:${msg.message}\n`
      output += msgText
    }
    output += '```'

    return output
  }

  controller.hears([/^check[\n\r]([\s\S]*)/], ['direct_message'], (bot, message) => {
    const msgBody = message.match[1]

    engine.executeOnText(msgBody).then(results => {
      if (! engine.isErrorResults(results)) {
        bot.reply(message, 'エラーは見つかりませんでした。')
        return
      }

      let output = ''
      output += 'エラーが見つかりました。\n\n'
      output += formatResults(results)

      bot.reply(message, output)
    })
  })
}

これで実装は完了です!簡単なのでぜひ試してみてください!

最後に

さて、今回は textlint を使った文字校正Botについてご紹介しました。

textlintはまだまだ発展途上にあるため実務でがっつり使うにはまだ少し時間がかかるかな、というのが実際に使ってみた所感です。 特に用字用語や送り仮名、誤字脱字の検出に関しては辞書ベースの検出になるためどうしても力不足であることは否めません。 Yahoo! 校正APIを使うことである程度カバーできますが、textlintのルールは誰でも簡単に作ることができるので今後そのあたりをカバーするルールが充実するといいなと思いました。

もし興味があればルール作りなどにも挑戦してみてください!よいBotライフを!