「行数カウント」で何をしたいのかをはっきりさせる
ここでの「行数カウント」は、文字列の中に「何行分のテキストがあるか」を数えるユーティリティのことです。
テキストエリアに何行入力されているか知りたい。
ログやコメントの「行数制限」をかけたい。
アップロードされたテキスト(CSV など)の行数をざっくり知りたい。
つまり、「改行をちゃんと扱って、行数を正しく数える」ことがゴールです。
まずは「改行コード」の違いをざっくり理解する
改行には種類がある
実は、改行は1種類ではありません。代表的にはこの3つがあります。
"\n" … LF(Unix系、macOS、Linux、最近のWeb)"\r\n" … CRLF(Windows)"\r" … CR(古いMacなど、ほぼレガシー)
業務で扱うテキストは、これらが混ざっていることがあると思っておいた方が安全です。
だからこそ、「行数カウント」は
「どの改行コードでもちゃんと1行として扱う」ことが大事なポイントになります。
一番基本の行数カウントユーティリティ
改行で分割して、配列の長さを数える
一番シンプルな発想はこうです。
- 改行で文字列を分割する。
- 分割された配列の「要素数」が行数になる。
ただし、さっきの「改行コードの違い」を吸収するために、
正規表現で「どの改行でも分割できるようにする」のがコツです。
function countLines(text) {
if (text == null) return 0;
const s = String(text);
if (s === "") return 0;
const lines = s.split(/\r\n|\r|\n/);
return lines.length;
}
JavaScriptここが重要ポイントです。
\r\n|\r|\n という正規表現で、
「CRLF」「CR」「LF」のどれでも分割できるようにしている。split の結果の配列の長さが、そのまま行数になる。
動きのイメージはこうです。
countLines("一行目"); // 1
countLines("一行目\n二行目"); // 2
countLines("一行目\r\n二行目\r\n三行目"); // 3
countLines(""); // 0
JavaScriptまずはこのレベルで、「行数を数える」という目的は達成できます。
「最後が改行で終わる」ケースをどう扱うか
空行も1行として数えるかどうか
例えば、こんな文字列を考えます。
"一行目\n二行目\n"
このとき、split(/\r\n|\r|\n/) の結果はこうなります。
["一行目", "二行目", ""]
つまり、最後に空文字の要素が1つ増えるので、length は 3 になります。
これを「3行」と数えるか、「2行」と数えるかは、要件次第です。
- テキストエリアの「見た目の行数」としては 3 行に見える。
- 「中身のある行数」としては 2 行と数えたいこともある。
ここをどうするかを、ユーティリティ側で決めておくとブレません。
「中身のある行だけ数える」バージョン
空行を除外して数える
「空行は行数に含めたくない」という要件なら、split したあとに「空文字の行を除外」してから数えます。
function countNonEmptyLines(text) {
if (text == null) return 0;
const s = String(text);
if (s === "") return 0;
const lines = s.split(/\r\n|\r|\n/);
const nonEmptyLines = lines.filter((line) => line.trim() !== "");
return nonEmptyLines.length;
}
JavaScriptここがポイントです。
line.trim() !== "" で、「空白だけの行」も空行として扱っている。
つまり、スペースやタブだけの行もカウントしない。
動きはこうなります。
countNonEmptyLines("一行目\n二行目\n"); // 2
countNonEmptyLines("一行目\n\n三行目"); // 2
countNonEmptyLines("一行目\n \n三行目"); // 2(空白だけの行も除外)
JavaScript「実質的な内容のある行数」を知りたいときには、このバージョンが便利です。
実務での使いどころと設計のポイント
「何を行数とみなすか」を先に決める
行数カウントは、一見単純ですが、
「何を1行とみなすか」で結果が変わる処理です。
空行も1行として数えるのか。
空白だけの行はどうするのか。
最後の改行で増える空行をどう扱うのか。
これを画面ごと・機能ごとにバラバラに決め始めると、
「ここでは 10 行までOKなのに、あっちでは 9 行でエラーになる」といったズレが出ます。
だからこそ、
export function countLines(...) { ... } // 見た目の行数
export function countNonEmptyLines(...) { ... } // 中身のある行数
JavaScriptのように、目的ごとに関数を分けておくのがきれいです。
「制限」とセットで使う
行数カウントは、単体で使うよりも「制限」とセットで使うことが多いです。
const maxLines = 5;
const lines = countLines(comment);
if (lines > maxLines) {
showError(`この欄は最大 ${maxLines} 行までです(現在 ${lines} 行)。`);
}
JavaScriptこうしておくと、ユーザーに「今何行使っているか」も伝えられるし、
「なぜエラーになったか」も分かりやすくなります。
ちょっとだけ手を動かしてみる
コンソールで、次のあたりを試してみてください。
countLines("一行目");
countLines("一行目\n二行目\n三行目");
countLines("一行目\n二行目\n");
countNonEmptyLines("一行目\n\n三行目");
countNonEmptyLines("一行目\n \n三行目");
JavaScript「どのケースで何行と数えられるか」を、自分の目で確かめてみてください。
そのうえで、自分のプロジェクトに
export function countLines(...) { ... }
export function countNonEmptyLines(...) { ... }
JavaScriptの2本を置いて、
「見た目の行数を知りたい → countLines」
「中身のある行数を知りたい → countNonEmptyLines」
という使い分けをルール化してみてください。
それだけで、あなたの「行数カウント」は
場当たり的な split("\n") から、
改行コードの違いと要件の違いをちゃんと意識した“業務レベルのユーティリティ”に一段レベルアップします。
