🔟
文字数をカウントするサイトを作った
文字数をカウントする機会は度々あるかと思います。
そんなときにお世話になっていたサイトが閉鎖したとのことで話題になっていました。
インターネットアーカイブには残っているので引き続き使うことはできるのですが、せっかくなので文字数のカウントについて調べ自分でも作ってみました。
作ったサイトはこちらです。より正確にカウントできるようになっています。
すべてクライアントで処理しているので通信は行いません。
元サイトのロジック
実際のコードとは少し異なりますが分かりやすさ優先で記載します。
以降のコードは 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
参考
X (Twitter) の文字数
公式ライブラリが OSS で公開されています。
全角として換算します。
import twitter from 'twitter-text';
Math.ceil(twitter.parseTweet(text).weightedLength / 2)
-
2024/04/16 リリースの Firefox 125 で対応される予定 ↩︎
Discussion