Java Tips | 文字列処理:ランダム文字挿入

Java Java
スポンサーリンク

ランダム文字挿入は「ちょっとした“ノイズ”や“識別子”を混ぜる」テクニック

ランダム文字挿入は、既存の文字列の中に「ランダムな文字」を差し込む処理です。
たとえば、IDの途中にランダム文字を混ぜて一意性を高めたいとき、
ログのトレースIDにランダムなサフィックスを付けたいとき、
テストデータとして「毎回少し違う文字列」を作りたいときなどに使えます。

ポイントは、「どこに」「どんな文字を」「何文字」挿入するかを、きちんと決めてユーティリティ化しておくことです。
そうすると、業務コード側は「ルールに名前をつけて呼ぶだけ」で済むようになります。


基本形:指定位置にランダム文字列を挿入する

まずは「アルファベット+数字」を挿入するシンプル版

一番基本となるのは、次のような処理です。
元の文字列、挿入位置、挿入するランダム文字数を受け取り、
その位置にランダム文字列を差し込んだ新しい文字列を返します。

import java.security.SecureRandom;

public final class RandomInsertUtil {

    private static final String DEFAULT_CHARS =
            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

    private static final SecureRandom RANDOM = new SecureRandom();

    private RandomInsertUtil() {}

    public static String insertRandom(String base, int position, int length) {
        if (base == null) {
            throw new IllegalArgumentException("base must not be null");
        }
        if (position < 0 || position > base.length()) {
            throw new IllegalArgumentException("position out of range: " + position);
        }
        if (length < 0) {
            throw new IllegalArgumentException("length must not be negative");
        }

        String randomPart = randomString(length);
        StringBuilder sb = new StringBuilder();
        sb.append(base, 0, position);
        sb.append(randomPart);
        sb.append(base.substring(position));
        return sb.toString();
    }

    private static String randomString(int length) {
        StringBuilder sb = new StringBuilder(length);
        int n = DEFAULT_CHARS.length();
        for (int i = 0; i < length; i++) {
            int idx = RANDOM.nextInt(n);
            sb.append(DEFAULT_CHARS.charAt(idx));
        }
        return sb.toString();
    }
}
Java

使い方のイメージは次の通りです。

String base = "ORDER-2025";
String result = RandomInsertUtil.insertRandom(base, 6, 4);
// 例: "ORDER-Ab3X-2025" のような文字列になる
System.out.println(result);
Java

ここで重要なのは、「挿入位置の扱い」と「ランダム生成の方法」です。
挿入位置は 0 以上 base.length() 以下でなければならないので、
範囲外なら例外を投げて「呼び出し側のバグ」として扱っています。
また、ランダム生成には SecureRandom を使っていて、
テストデータだけなら java.util.Random でも構いませんが、
IDやトークンに近い用途なら SecureRandom を使うのが基本です。


ランダム挿入位置もランダムにしたい場合

文字列のどこかにランダムで差し込む

「どこに挿入されるかもランダムでいい」というケースもあります。
その場合は、挿入位置自体をランダムに決めてしまいます。

public static String insertRandomAtRandomPosition(String base, int length) {
    if (base == null) {
        throw new IllegalArgumentException("base must not be null");
    }
    if (length < 0) {
        throw new IllegalArgumentException("length must not be negative");
    }
    int position = RANDOM.nextInt(base.length() + 1); // 0〜base.length() のどこか
    return insertRandom(base, position, length);
}
Java

使い方は次のようになります。

String base = "SESSION";
String result = RandomInsertUtil.insertRandomAtRandomPosition(base, 3);
// 例: "SESxYION", "SExxSSION", "SESSIONabc" など、位置も中身も毎回変わる
System.out.println(result);
Java

ここで深掘りしたいのは、「ランダムの範囲をどう決めるか」です。
nextInt(base.length() + 1) としているのは、
先頭(0)から末尾の「後ろ」(base.length())まで、
どこに挿入してもよい、という意味です。
このように、インデックスの範囲をきちんと意識して書くことが、
文字列操作ではとても大事になります。


挿入に使う文字セットを切り替えられるようにする

英数字だけ、数字だけ、記号も含める、などを選べるようにする

用途によって、「どんな文字を使ってよいか」は変わります。
ログ用のトレースIDなら英数字だけで十分かもしれませんし、
テスト用のノイズなら記号も混ぜたいかもしれません。

そこで、「文字セットを引数で渡せる」バージョンを用意しておくと便利です。

public static String insertRandom(
        String base, int position, int length, String charSet) {

    if (base == null) {
        throw new IllegalArgumentException("base must not be null");
    }
    if (position < 0 || position > base.length()) {
        throw new IllegalArgumentException("position out of range: " + position);
    }
    if (length < 0) {
        throw new IllegalArgumentException("length must not be negative");
    }
    if (charSet == null || charSet.isEmpty()) {
        throw new IllegalArgumentException("charSet must not be empty");
    }

    String randomPart = randomString(length, charSet);
    StringBuilder sb = new StringBuilder();
    sb.append(base, 0, position);
    sb.append(randomPart);
    sb.append(base.substring(position));
    return sb.toString();
}

private static String randomString(int length, String charSet) {
    StringBuilder sb = new StringBuilder(length);
    int n = charSet.length();
    for (int i = 0; i < length; i++) {
        int idx = RANDOM.nextInt(n);
        sb.append(charSet.charAt(idx));
    }
    return sb.toString();
}
Java

使い方の例として、数字だけを挿入したい場合は次のようにします。

String base = "USER-";
String result = RandomInsertUtil.insertRandom(base, base.length(), 6, "0123456789");
// 例: "USER-493028" のような文字列になる
System.out.println(result);
Java

ここでの重要ポイントは、「ルールをユーティリティの引数で表現する」ことです。
「英数字だけ」「数字だけ」「大文字だけ」といった違いを、
呼び出し側が文字セットとして渡せるようにしておくと、
ユーティリティの再利用性が一気に上がります。


実務での使いどころと注意点

トレースIDや一時キーにランダム文字を混ぜる

例えば、ログのトレースIDに「日時+ランダム文字」を使いたい場合、
次のようなコードになります。

String baseId = "20260204-123456";
String traceId = RandomInsertUtil.insertRandom(baseId, baseId.length(), 4);
// 例: "20260204-123456aZ9k" のようなID
Java

これにより、「ある程度意味のあるID(日時)」に、
「衝突しにくいランダム部分」を足すことができます。

ただし、セキュリティトークンや認証用の値として使う場合は、
長さや文字セット、生成方法(必ず SecureRandom を使うこと)を
セキュリティ要件に合わせて慎重に設計する必要があります。

テストデータに「毎回少し違う文字列」を作る

テスト用に、「ベースは同じだけど、毎回少し違う文字列」が欲しいことがあります。

String base = "TEST-DATA-";
for (int i = 0; i < 5; i++) {
    String value = RandomInsertUtil.insertRandom(base, base.length(), 3);
    System.out.println(value);
}
Java

このようにしておくと、
「パターンは同じだが値は毎回違う」テストデータを簡単に作れます。

ここでの注意点は、「テストで使うランダム」と「本番で使うランダム」を混同しないことです。
テストでは再現性が欲しい場合もあるので、
SecureRandom ではなく Random に固定シードを与える、
といった設計もありえます。
一方、本番のIDやトークンでは、予測されにくさが重要なので SecureRandom 一択です。


まとめ:ランダム文字挿入ユーティリティで身につけたい感覚

ランダム文字挿入は、「既存の文字列に少しだけランダム性を足す」ためのテクニックです。
単に「ランダムな文字列を作る」だけでなく、
「どこに挿入するか」「どんな文字を使うか」「何文字挿入するか」を
ユーティリティとしてきちんと形にしておくことで、
業務コード側がとても読みやすく、意図が伝わりやすくなります。

もしあなたのコードのどこかに、
その場しのぎのランダム文字生成と文字列結合が散らばっているなら、
それを一度「ランダム文字挿入ユーティリティ」にまとめてみてください。

その小さな整理が、「ルールの見える文字列処理」を書けるエンジニアへの、確かな一歩になります。

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