ことさら−古都プログラマーの更級日記

京都でお寺を回りながら御朱印集めをしていたエンジニアのブログ。おもに技術的なはなしとか日常的なはなし。たまにカメラの話や競馬の話も書きます。

Markdownで書かれた文章の文字数をカウントできるサービスを作りました

表題の通り、Markdownで書かれた文章(ブログ記事やらQiitaやらGitHub Markdownやら)の文字数を数えられるサービスを作りました。もちろん、設定をいじればMarkdown形式でない文章についてもカウントすることができます

Markdown対応文字数カウンター

作ったきっかけ

最近ブログ記事を書く時はほとんどMarkdownで書いています。コードブロックや見出しが書きやすくて、慣れるとサクサクと書けます。エンジニアの方はMarkdownを使ってブログを書いている方がほとんどなのではないでしょうか。

また、ブログの文章の文字数をカウントしたい時があります。SEOを意識した記事なんかだと文字数も重要ですからね。

しかし、Markdownで書いた文章の文字数を数えるのは面倒です。Markdownに対応している文字数カウンターがWebサービスでは意外と見つかりません。レンダリングした文字をコピーして、改行や空白を除いた文字数をカウントさせるなどの工夫が必要です。

さらにMarkdown文章ならでわの要望があります。例えば「引用は文字数に含めたくない」「コードブロックは文字数に含めたくない」等です。

こういったものが見つからなかった結果、「作っちゃえ」という結論になりました。

実装(技術的な話)

コードはGitHubで公開しています。

github.com

コードは簡潔で、すべて index.html に書かれています。

https://yoshikyoto.github.io/markdown_string_counter/ こちら見ての通り GitHub Pages の静的ページです。文字数カウント部分はすべてJavaScriptで書かれています。使っているライブラリは以下の2つです。

Vue.js

jp.vuejs.org

JSのMVVM(Model-View-ViewModel)フレームワーク的なやつのVue.jsを使っています。最近MVVMだったり、Fluxがどーのだみたいなのを使うとき*1、だいたいはVue.jsを使うか、React.jsを使うかみたいな話になってきます。サクッと使えるのならVue.jsが良いかなと思っています。

https://github.com/yoshikyoto/markdown_string_counter/blob/master/index.html あたりを見てもらえれば分りますが、

<script src="https://cdn.jsdelivr.net/npm/vue"></script>

こうやってHTMLからVue.jsを読み込めばとりあえず使えるようになります。

本体は <body> の最後の <script> の中身です。このあたりです。

<script>
  var app = new Vue({
    el: '#app',
    ...
  });
</script>

el: #app を指定することで、このDOM以下がVueの管理下になります。HTMLの中に <div id="#app">...</div> の部分があるかと思います。テンプレートの部分はHTML、ロジックの部分はJSというかき分けがこれだけでできます。注意点として、<script><div id="#app#">...</div> より後に書いて下さい。scriptが実行されるタイミングでDOMがレンダリングされている必要があるからです。

あとは見たら分かるように、 <textarea v-model="text" cols="100" rows="25"></textarea> こう書くと Vueの方の text: と連動したり、

<h2>文字数: {{ getCount() }}</h2> こう書くとVueの getCount() { と連携してくれたりします。

このあたり詳しくはVue.jsのドキュメントを参照してください。

marked

JS側で処理を完結させるためにもJS側でMarkdownを解釈させる必要がありました。文章をコピペしてから「カウント」ボタンを押して文字をサーバーサイドに送信して...なのはイケてないですからね。あとは、まだ公開していない文章をサーバーサイドに送るのはやはり嫌なものです。今回はMarkdown解釈のライブラリとしてmarkedを採用しました。

github.com

JavaScriptのMarkdwonライブラリの検討の際には、以下のブログ記事等を参考にしました。

kannokanno.hatenablog.com

qiita.com

ちょっと古い記事ですが、確かにmarkedがGitHub Flavor Markdownにも対応していて一番イケてそうな感じがしましたし、しっかりと最近までコミットがされていたため採用しました。

JS本体は https://github.com/chjj/marked/blob/master/lib/marked.js に存在していて、とりあえずこれを<script> で突っ込んどけば使えるのもいいですね。

今後

今回は「とりあえず自分の欲しい機能をつける」事を目標にして「Markdownで書かれた文章の文字数を数える」「コードブロックを無視する」「引用部分を無視する」だけを実装しました。ただ、多くの人が利用するため、色々な要望があるかと思います。今後付けたい機能などをまとめておきたいと思います。

付けたい機能

付けたいと思っている機能は以下の通りです。

  • 設定を保存する機能(すぐ付けられそうな気がしているのでつけたい)
  • 章や節ごとに文字数を数える機能(UIやロジックが複雑になりそうなので付けていない)
  • マークダウンを表示する機能(そこまで必要なのか?という疑問があるので余裕があれば)

OGPの設定

実は今まで僕が作ったサービス、OGPをちゃんと付けたことがないんですよね。OGPとはOpen Graph Protocolで、twitterとかにシェアした時にタイトルとかサムネ画像とかが出てくるアレです。公式っぽいドキュメントは以下です。

ogp.me

かるくつけようとしてみたんですが、付きませんでした。GitHub Pagesが対応していないのかも?いずれにせよもうチョット勉強してみます。詳しくはまた実装できたりしたらブログを書きます。

機能の要望・プルリクエス

利用者が増えると要望は色々出てくるかと思います。「表は文字数に含めないような設定が欲しい」「リストは文字数に含めないような設定が欲しい」「もうちょっとUIはこんな感じの方が使いやすい」などなど...とはいえどれが本当に必要な機能なのか分かりません。

そこで、もし欲しい機能がございましたら、是非お気軽におっしゃってもらえればと思います。実装することを確約はできませんが、要望を出すだけならタダです。

例えば以下の経路で要望できます。

当然ですが、一番確実に実装されるのはプルリクエスです。

一番気づきやすいのはtwitterですので、例えば「プルリクエストを出したのに反応がない」「ブログにコメントを書いたけど気づいているのか不安」という場合はtwitterまでご連絡ください。要望が多すぎて対応できない、ということがなければ反応が返ってくるかと思います。

要望を出す際の注意点

これは、僕に要望を出す場合に限らないのですが、可能であれば「何故その要望があるのか」や「具体的にどうすればいいか」なども添えて分かりやすく書いていただければと思います。一言だけの要望でも、もらえないよりはもらえたほうがありがたいのですが、「なるほど実装しよう」となるための情報が欲しいです。

例: 「章ごと文字数を出してくれる機能が欲しいです」

→ 要望があることに関しては理解できます。ただ、UIはどうしようかな、といった問題が出てきます。機能追加するとUIが複雑になってしまうのは性で、ぱっとみて使いやすいUIにするためには機能を削ぐことも大切です。

わかりやすい例: 「SEOのため記事を書いているのですが、章ごとの文字数制限があるので、章毎ごとの文字数が知りたいです。UIは〜な感じがいいですが、複雑なので、とりあえずテキストエリアで選択した箇所の文字数をカウントできる機能でもよいです」

→ 機能が欲しい理由がはっきりしていてUIの例があったほうが実装しやすいですし、「とりあえず後者の機能なら実装しやすいしそちらを実装するか...」となります。

とはいえ、まずはそういったことを気にせず要望を送るのも重要でしょう。「多数の需要がある」ことが分かると実装しやすくなるので、要望を送らないよりは送った方が良いかと思います。

*1:Virtual DOM ライブラリって言ったらいいんですかね。この辺の用語がまだふわっとしている。