🔟

文字数をカウントするサイトを作った

2024/04/01に公開

文字数をカウントする機会は度々あるかと思います。
そんなときにお世話になっていたサイトが閉鎖したとのことで話題になっていました。
インターネットアーカイブには残っているので引き続き使うことはできるのですが、せっかくなので文字数のカウントについて調べ自分でも作ってみました。

https://web.archive.org/web/20240327085935/http://www1.odn.ne.jp/megukuma/count.htm

作ったサイトはこちらです。より正確にカウントできるようになっています。
すべてクライアントで処理しているので通信は行いません。

https://snowcait.github.io/count-characters/
https://github.com/SnowCait/count-characters

元サイトのロジック

実際のコードとは少し異なりますが分かりやすさ優先で記載します。
以降のコードは let text; に文字数をカウントしたいテキストが入っているものとします。

文字数(スペース込み)

text.replace('\n', '').length

文字数(スペース無視)

text.replace(/\s| /g, '').length

行数

(text.match(/\n/g)?.length ?? 0) + 1

段落数

(text.match(/\n(?: |\s+||||||||||\(|\"|\')./g)?.length ?? 0) + 1

原稿用紙換算(400x?枚)

Math.ceil(text.replace('\n', '').length / 400)

課題

このままでもそんなに困らないと思いますが JavaScript の length を使っているので一部の文字を多めにカウントしてしまいます。
また X (Twitter) の文字数カウントは URL を半角 23 文字として固定カウントしたり少し特殊なのでそちらにも対応したいところです。

対応が必要な文字

  • サロゲートペア
  • 異体字セレクタ
  • 結合文字
  • ゼロ幅接合子(ZWJ、絵文字シーケンス)

対応方法

これらの対応を個々にやるのは面倒なのでライブラリを使います。
Intl.Segmenter を使うのが一番良いとは思うのですが Firefox が現時点では非対応[1]なのでもうしばらくは graphemesplit を使用しておくのが良いかと思います。

graphemesplit
import split from 'graphemesplit';

split(text).length

一応 Intl.Segmenter のコードも載せておきます。

Intl.Segmenter
[...new Intl.Segmenter('ja', { granularity: 'grapheme' }).segment(text)].length

参考

https://qiita.com/bon127/items/491b25e90208188dafbd
https://qiita.com/suin/items/3da4fb016728c024eaca
https://blog.jxck.io/entries/2017-03-02/unicode-in-javascript.html

X (Twitter) の文字数

公式ライブラリが OSS で公開されています。
全角として換算します。

https://github.com/twitter/twitter-text/tree/master/js

import twitter from 'twitter-text';

Math.ceil(twitter.parseTweet(text).weightedLength / 2)
脚注
  1. 2024/04/16 リリースの Firefox 125 で対応される予定 ↩︎

Discussion