Java Tips | 文字列処理:行数カウント

Java Java
スポンサーリンク

行数カウントは「テキストの大きさ」を測る基本ツール

行数カウントは、「この文字列は何行あるか?」を数える処理です。
ログの行数、テキストエリア入力の行数、ファイル内容の行数チェックなど、業務ではかなりよく出てきます。

そして行数カウントで一番大事なのは、
「どの文字を“改行”とみなすか」「最後の空行を数えるかどうか」
この2つをちゃんと決めることです。
ここを曖昧にしたまま書くと、OSやデータの違いでズレが出ます。


改行コードの違いをまず理解する

LF / CRLF / CR の3種類がある

行数カウントの前提として、改行コードの種類を知っておく必要があります。

"\n"(LF) … Linux, macOS など
"\r\n"(CRLF) … Windows
"\r"(CR) … 古いMacなどの名残データ

もし、単純に split("\n") だけで行数を数えると、
Windows由来の "\r\n"\r が行末に残ったり、
"\r" だけの改行を認識できなかったりします。

業務で外部ファイルや他システムからのテキストを扱うなら、
「LF も CRLF も CR も、全部“改行”として扱う」
という前提で行数カウントを書くのが安全です。


正攻法:split("\R") でどの改行でも行数を数える

Java 8以降なら「任意の改行」を一発で扱える

Java 8以降の正規表現には \R という便利なメタ文字があります。
これは「任意の改行シーケンス(LF / CRLF / CR など)」を意味します。

これを使えば、改行コードの違いを意識せずに行数を数えられます。

public final class LineCountUtil {

    private LineCountUtil() {}

    public static int countLines(String text) {
        if (text == null || text.isEmpty()) {
            return 0;
        }
        String[] lines = text.split("\\R");
        return lines.length;
    }
}
Java

使い方はこうです。

String text = "1行目\n2行目\r\n3行目\r4行目";

System.out.println(LineCountUtil.countLines(text)); // 4
System.out.println(LineCountUtil.countLines(""));   // 0
System.out.println(LineCountUtil.countLines(null)); // 0
Java

ここで押さえておきたい重要ポイントは二つです。

一つ目は、「改行コードの違いを \\R に丸投げしている」ことです。
自分で \r\n|\n|\r と書いてもよいですが、\\R を使うと読みやすく、ミスも減ります。

二つ目は、「null や空文字のときは 0 行とみなす」というポリシーを決めていることです。
これにより、呼び出し側は LineCountUtil.countLines(text) をそのまま比較に使えて、
毎回 null チェックを書かなくて済みます。


「最後が改行で終わるときの空行」をどう扱うか

"1行目\n2行目\n" は 2行か?3行か?

行数カウントでよくハマるのが、
「最後が改行で終わる場合、その後の空行を数えるかどうか」 です。

例えば、次の文字列を考えます。

String text = "1行目\n2行目\n";
Java

人によっては「2行」と数えますし、
「3行目は空行だから3行」と数える考え方もあります。

split("\\R") の挙動はこうなります。

String text = "1行目\n2行目\n";
String[] lines = text.split("\\R");
System.out.println(lines.length); // 2
Java

末尾の空行はカウントされません。

ここで大事なのは、
「どちらが正しいか」ではなく「自分のシステムではどちらにするかを決める」
ということです。

もし「末尾の空行も1行として数えたい」要件があるなら、
自分でループして数える実装にする必要があります。


末尾の空行も含めて「改行の数+1」で数える方法

改行文字を数えて行数を求める

「末尾の空行も含めて、改行の数+1を行数とする」
というルールで数えたい場合は、こういう実装もできます。

public static int countLinesIncludingLastEmpty(String text) {
    if (text == null || text.isEmpty()) {
        return 0;
    }
    int count = 1; // 少なくとも1行はある前提
    for (int i = 0; i < text.length(); i++) {
        char c = text.charAt(i);
        if (c == '\n') {
            count++;
        } else if (c == '\r') {
            count++;
            // CRLF の場合、次の \n をスキップ
            if (i + 1 < text.length() && text.charAt(i + 1) == '\n') {
                i++;
            }
        }
    }
    return count;
}
Java

使い方はこうです。

System.out.println(countLinesIncludingLastEmpty("1行目\n2行目\n")); // 3
System.out.println(countLinesIncludingLastEmpty("1行目\n2行目"));   // 2
Java

ここでの重要ポイントは、
「CRLF(\r\n)を1つの改行として扱うために、\r の後ろの \n をスキップしている」
ことです。

このように、自前でループを書くと柔軟に制御できますが、
そのぶんバグを埋め込みやすくもなります。

だからこそ、まずは「末尾の空行を数える必要が本当にあるか?」を冷静に考えるのが大事です。
多くの業務では、split("\\R") の挙動(末尾の空行は数えない)で十分なことが多いです。


実務での行数カウントの使いどころ

例1:テキストエリアの行数制限

「1行1件で最大100行まで入力できます」といった画面を考えます。

String input = request.getParameter("items");
int lineCount = LineCountUtil.countLines(input);

if (lineCount > 100) {
    errors.add("入力できる行数は最大100行までです。");
}
Java

ここでは、「末尾の空行は行数に含めなくてよい」という前提で countLines を使っています。

例2:ログの行数をざっくり把握する

ログファイルの内容を文字列として読み込んだあと、
「何行あるか」をざっくり知りたい場面もあります。

String logText = Files.readString(path);
int lines = LineCountUtil.countLines(logText);
System.out.println("ログ行数: " + lines);
Java

ここでのポイントは、
「OSや生成元が違っても、行数が安定して数えられる」
という安心感です。


まとめ:行数カウントユーティリティで身につけたい感覚

行数カウントはシンプルに見えて、実は設計のセンスが出る処理です。

押さえておきたいのは次の感覚です。

改行コードは \n だけではなく、\r\n\r もある
Java 8以降なら split("\\R") で「どの改行でも分割できる」
null や空文字は 0 行とみなすポリシーにしておくと扱いやすい
末尾の空行を行数に含めるかどうかは、要件として明確に決める

もしあなたのコードのどこかに、

int lines = text.split("\n").length;
Java

のような行がそのまま書かれていたら、
それを題材にして、LineCountUtil.countLines のようなユーティリティに置き換えてみてください。

その小さな改善が、
「OSや外部システムの違いに強い、堅牢な文字列処理」を書けるエンジニアへの、確かな一歩になります。

タイトルとURLをコピーしました