Java Tips | 文字列処理:文字列反転

Java Java
スポンサーリンク

文字列反転は「順番をひっくり返す」だけ…だけど侮れない

文字列反転は、その名の通り「文字の並び順を逆にする」処理です。
"ABC""CBA"
"山田太郎""郎太田山"

一見すると「ただの遊び」みたいに見えますが、
業務でもログの加工、簡易的な暗号化、アルゴリズムの練習、テキスト処理の前処理など、
地味に出番があります。

そして何より、「文字列と配列」「インデックス」「ループ」の感覚を鍛えるのに最高の題材です。
ここを丁寧に押さえておくと、他の文字列処理も一気に理解しやすくなります。


一番簡単な方法:StringBuilder#reverse() を使う

実務ならまずはこれで十分

Javaには、すでに「文字列を反転するメソッド」が用意されています。
StringBuilder(または StringBuffer)の reverse() です。

public final class StringReverser {

    private StringReverser() {}

    public static String reverse(String text) {
        if (text == null) {
            return null;
        }
        return new StringBuilder(text).reverse().toString();
    }
}
Java

使い方はとてもシンプルです。

System.out.println(StringReverser.reverse("ABC"));      // CBA
System.out.println(StringReverser.reverse("山田太郎")); // 郎太田山
System.out.println(StringReverser.reverse("12345"));    // 54321
System.out.println(StringReverser.reverse(""));         // 空文字は空文字のまま
System.out.println(StringReverser.reverse(null));       // null は null のまま
Java

ここで重要なのは二つです。

一つ目は、「実務では“まず標準ライブラリでできないか”を考える」という姿勢です。
自分でループを書かなくても、StringBuilder#reverse() がすでに最適化された実装を持っています。
「車輪の再発明をしない」というのは、プロのプログラマーの大事な習慣です。

二つ目は、「null をどう扱うかを決めている」ことです。
ここでは「null が来たら null を返す」という方針にしていますが、
「null は空文字にする」「例外を投げる」など、システムのポリシーに合わせて決める必要があります。


あえて自分で実装してみる:配列とループで反転する

「インデックス」と「左右から詰める」感覚を身につける

学習としては、reverse() に丸投げする前に、
一度「自分で反転処理を書いてみる」のがおすすめです。

文字列を反転する基本パターンはこうです。

  1. 文字列を char[] に変換する
  2. 左端と右端の文字を入れ替える
  3. 左右から中央に向かって進めていく

コードにするとこうなります。

public final class StringReverserManual {

    private StringReverserManual() {}

    public static String reverse(String text) {
        if (text == null) {
            return null;
        }
        char[] chars = text.toCharArray();
        int left = 0;
        int right = chars.length - 1;

        while (left < right) {
            char tmp = chars[left];
            chars[left] = chars[right];
            chars[right] = tmp;
            left++;
            right--;
        }
        return new String(chars);
    }
}
Java

使い方は先ほどと同じです。

System.out.println(StringReverserManual.reverse("ABC"));      // CBA
System.out.println(StringReverserManual.reverse("山田太郎")); // 郎太田山
Java

ここで深掘りしたいポイントは三つです。

一つ目は、「toCharArray() で“文字列を配列にしている”」ことです。
String は不変(immutable)なので、直接中身を書き換えることはできません。
一度 char[] にしてから、配列を入れ替え、最後に新しい String を作っています。

二つ目は、「左右から中央に向かって入れ替えると、1回の走査で済む」ことです。
leftright を使って、
[0][n-1][1][n-2]…というペアを入れ替えていくことで、
効率よく反転できます。

三つ目は、「while (left < right) という条件の意味を理解する」ことです。
左右が交差したら(left >= right)、もう入れ替える必要はありません。
この条件を間違えると、無限ループになったり、二度入れ替えて元に戻ったりします。
こういう「境界条件」を丁寧に考える癖が、アルゴリズム全般で効いてきます。


文字列反転の“落とし穴”:Unicodeとサロゲートペア

絵文字や一部の漢字で「1文字=1char」ではない問題

ここまでの話は、「1文字が1つの char で表現される」という前提で成り立っています。
しかし、Javaの char は「UTF-16の1ユニット」であり、
一部の文字(絵文字、異体字など)は「2つの char の組み合わせ(サロゲートペア)」で表現されます。

例えば、絵文字を含む文字列を反転してみます。

String s = "A😊B";
System.out.println(s);                         // A😊B
System.out.println(StringReverser.reverse(s)); // B😊A になることもあれば、環境によっては文字化けすることも
Java

"😊" は内部的には2つの char で表現されているので、
単純に char 単位で入れ替えると、「ペアがバラバラになる」可能性があります。

実務で「絵文字や特殊文字を含むテキストを正しく反転したい」という要件はあまり多くありませんが、
char と“見た目の1文字”は必ずしも一致しない」
という事実を知っておくことは、とても大事です。

本気でUnicode対応の反転をやるなら、
codePoint 単位で扱う必要があります。

public static String reverseByCodePoint(String text) {
    if (text == null) {
        return null;
    }
    int[] codePoints = text.codePoints().toArray();
    int left = 0;
    int right = codePoints.length - 1;
    while (left < right) {
        int tmp = codePoints[left];
        codePoints[left] = codePoints[right];
        codePoints[right] = tmp;
        left++;
        right--;
    }
    return new String(codePoints, 0, codePoints.length);
}
Java

これなら、「見た目の1文字」単位で反転できます。
ただし、ここまでやるかどうかは要件次第です。
大事なのは、「char ベースの反転には限界がある」ということを知っておくこと。
知らないまま使うのが一番危険です。


文字列反転の実務での使いどころ

単なるお遊びで終わらせない

「反転なんて、実務で使う?」と思うかもしれませんが、
意外と出番があります。

例えば、こんな場面です。

ログやIDの簡易的な難読化(本番ではちゃんとした暗号化を使うべきですが、テスト用などで)
右から何文字目、のような処理を反転してから左から処理することでシンプルに書く
アルゴリズムの練習問題(回文判定、左右対称チェックなど)

例えば、「文字列が回文(前から読んでも後ろから読んでも同じ)かどうか」を判定するユーティリティは、
反転を使うと簡単に書けます。

public final class PalindromeUtil {

    private PalindromeUtil() {}

    public static boolean isPalindrome(String text) {
        if (text == null) {
            return false;
        }
        String reversed = StringReverser.reverse(text);
        return text.equals(reversed);
    }
}
Java

使い方はこうです。

System.out.println(PalindromeUtil.isPalindrome("level")); // true
System.out.println(PalindromeUtil.isPalindrome("abc"));   // false
Java

ここでのポイントは、「反転処理を“部品”として持っておくと、別のユーティリティの中で再利用できる」ことです。
一度 StringReverser を作っておけば、
「回文チェック」「右からのインデックス処理」など、いろいろな場面で使い回せます。


まとめ:文字列反転ユーティリティで身につけたい感覚

文字列反転は、見た目はシンプルですが、
「文字列」「配列」「インデックス」「ループ」「Unicode」など、文字列処理の基礎がぎゅっと詰まった題材です。

実務目線で押さえておきたいのは、まず

StringBuilder#reverse() を素直に使う
null の扱い方を決める

という二つ。

学習目線では、

char[] にして左右から入れ替える実装を書いてみる
境界条件(left < right)の意味を理解する
char と“見た目の1文字”が一致しない場合があることを知る

という三つを、ぜひ自分の手で試してみてほしいです。

もしあなたのコードのどこかに、
「右から何文字目を取りたい」「末尾から順に処理したい」といったロジックがあれば、
一度「文字列を反転してから、左から処理する」という書き方に置き換えてみてください。

その小さな練習が、
「文字列を自在に扱えるプログラマー」への、確かな一歩になります。

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