背景
自分のサイトに、文章を貼ると読み終わるまでの目安の時間を出すツールを置いています。
ブログ記事の冒頭に「約3分で読めます」と書きたくて、毎回なんとなくで書いていたのが気持ち悪かったので作りました。
作るときに、英語向けの「1分あたり◯単語」の計算をそのまま日本語に当てたら、ほぼ0秒になりました…。
その理由と、どう数えればいいかの備忘録です。
結論
空白で区切って単語を数える方法は、日本語では使えません。
日本語の文には単語の間に空白が無いので、段落まるごとが1単語になります。
日本語の読了時間は、文字数で数えるのが手堅いです。
どうしても単語で数えたいなら、Intl.Segmenter を使います。
ツールの計算
ツールでは、テキストエリアの中身 t を受け取って、下記のように数えています。
mode は「文字/分」と「単語/分」の切り替え、speed はその速さで、既定は 500文字/分 と 250単語/分 にしています(この既定値は私が決めた目安です)。
// t: テキストエリアに貼られた文章
var chars = Array.from(t).length; // 文字数(サロゲートペアも1文字)
var trimmed = t.trim();
var words = trimmed === '' ? 0 : trimmed.split(/\s+/).length; // 空白区切りの単語数
var amount = mode === 'cpm' ? chars : words;
var seconds = Math.round(amount / speed * 60);
Array.from(t) は、文字列を1文字ずつの配列にする書き方だ。
t.length だと絵文字などが2と数えられるので、こちらを使っています。
split(/\s+/) は、空白・改行・タブが1つ以上続くところで区切る、という意味です。
実際に数えてみた
下記の日本語と英語で、文字数と単語数を出してみました(Node.js v24.11.1)。
今日は良い天気なので、近所の公園まで散歩に行きました。
I went for a walk to the park because the weather was nice today.
結果は下記です。
日本語: chars 27, words 1
英語: chars 65, words 14
英語は14単語と、見たとおりの数になっています。
日本語は27文字あるのに、単語は1つです。
空白が1つも無いので、split しても文全体が1要素のまま残ります。
この文を80回つなげた2,160字の文章でも、単語数は1のままでした。
そのため 250単語/分 で計算すると、読了時間は「0分0秒」になります。
同じ文章を 500文字/分 で計算すると「4分19秒」でした。
Intl.Segmenter で単語に分ける
Intl.Segmenter は、文字列を言語の規則に合わせて「文字」「単語」「文」に分割する、JavaScript の標準の仕組みだ。
仕様は下記にあります。
https://tc39.es/ecma402/#segmenter-objects
下記のように、granularity: 'word' を指定して、単語らしい部分(isWordLike が true のもの)だけを数えます。
句読点や空白は isWordLike が false になるので、自動で除かれます。
const s = '今日は良い天気なので、近所の公園まで散歩に行きました。';
const seg = new Intl.Segmenter('ja', { granularity: 'word' });
const words = [...seg.segment(s)].filter(x => x.isWordLike);
console.log(words.length);
console.log(words.map(x => x.segment).join('|'));
出力は下記になりました。
14
今日|は|良い|天気|なので|近所|の|公園|まで|散歩|に|行き|ま|した
日本語でも、それっぽい単位で14個に分かれているのがわかると思います。
「行き|ま|した」のように、人が思う区切りとは少し違うところもあります。
2,160字の文章だと1,120単語になり、250単語/分 で「4分29秒」でした。
文字数で出した 4分19秒 と、だいたい近い値です。
それでもツールを文字数にしている理由
Intl.Segmenter の分け方は、ブラウザが持っている辞書(ICU という国際化ライブラリ)に依存します。
なので、同じ文章でもブラウザや版によって単語数が変わる可能性がある、と思っています。
読了時間はもともと目安なので、どこで数えても同じになる文字数のほうが、扱いやすい気がします。
単語に分けた結果は、助詞の「は」や「の」も1単語に数えるので、英語の単語数と同じ感覚で読めるわけでもありません。
作ったツールはここに置いています。
https://hashitosystem.com/tools/readtime/
日本語の読了時間を出すなら、空白区切りの単語数ではなく、Array.from(s).length の文字数で計算します。
本記事はAI補助で執筆した、個人開発の紹介記事です。