Java
 Computer >> コンピューター >  >> プログラミング >> Java

【Java入門】文字列をすべての部分文字列に分割して取得するプログラムの書き方

本記事では、Javaを使って1つの文字列を複数の部分文字列(サブストリング)に分割し、その一覧を取得する方法を解説します。

まず用語の確認から始めましょう。文字列(String)とは、1つ以上の文字が並んだデータ型であり、ダブルクォーテーション(" ")で囲んで表現します。そして、その文字列の一部として切り出されたものを部分文字列(substring)と呼びます。

処理内容のイメージ

具体的な動作を見てみましょう。例えば、次のような入力があったとします。

入力文字列:JVM

この場合、期待される出力は以下の通りです。元の文字列から取り出せるすべての部分文字列が列挙されます。

ArrayListとして出力された部分文字列の一覧:
[J, JV, JVM, V, VM, M]

分割後の部分文字列:
(1) "J"
(2) "JV"
(3) "JVM"
(4) "V"
(5) "VM"
(6) "M"

アルゴリズムの手順

この処理は、以下のステップで実現できます。

Step 1 - 処理を開始する
Step 2 - 文字列 input_string と、ArrayList 型の string_list を宣言する
Step 3 - 値を定義する
Step 4 - 二重ループで文字列の長さ分だけ繰り返し処理を行い、
        取り出したすべての部分文字列をリストに追加する。
        これがコンソールに表示する結果となる。
Step 5 - ArrayListとして表示するために、カウンターを初期化し、
        結果を順番に走査しながらカウンターを増加させる。
        これにより、部分文字列の総数も求められる。
Step 6 - 結果を表示する
Step 7 - 処理を終了する

実装例1:mainメソッドにまとめて記述する方法

最初の例では、すべての処理をmainメソッド内に直接記述します。シンプルなスクリプト的な書き方です。

import java.io.*;
import java.util.ArrayList;
public class SubString {
    public static void main(String[] args) {
        System.out.println("必要なパッケージがインポートされました");
        String input_string = "JVM";
        System.out.println("対象の文字列: " +input_string);
        int i, j;
        int string_length = input_string.length();
        ArrayList<String> string_list = new ArrayList<String>();
        for (i = 0; i < string_length; i++) {
            for (j = i + 1; j <= string_length; j++) {
                string_list.add(input_string.substring(i, j));
            }
        }
        ArrayList<String> result = string_list;
        System.out.println( "\nArrayListとして出力された部分文字列の一覧: ");
        System.out.println(result);
        System.out.println( "\n分割後の部分文字列: ");
        int count = 1;
        for (String it : result) {
            System.out.println("(" + count + ") \"" + it + "\"");
            count++;
        }
    }
}

実行結果

必要なパッケージがインポートされました
対象の文字列: JVM

ArrayListとして出力された部分文字列の一覧:
[J, JV, JVM, V, VM, M]

分割後の部分文字列:
(1) "J"
(2) "JV"
(3) "JVM"
(4) "V"
(5) "VM"
(6) "M"

コードのポイント

外側のループ変数 i が開始位置、内側のループ変数 j が終了位置を表しています。substring(i, j) は「i番目の文字からj番目の直前まで」を切り出すため、この二重ループにより、長さ1の部分文字列から文字列全体まですべての組み合わせを網羅的に取得できます。

実装例2:オブジェクト指向スタイルで関数化する方法

次の例では、部分文字列を生成する処理を独立したメソッドに切り出し、オブジェクト指向プログラミング(OOP)らしい構造にしています。処理の再利用性が高まり、コードの見通しも良くなります。

import java.io.*;
import java.util.ArrayList;
public class SubString {
    public static ArrayList<String> split_string(String input_string) {
        int i, j;
        int string_length = input_string.length();
        ArrayList<String> string_list = new ArrayList<String>();
        for (i = 0; i < string_length; i++) {
            for (j = i + 1; j <= string_length; j++) {
                string_list.add(input_string.substring(i, j));
            }
        }
        return string_list;
    }
    public static void main(String[] args) {
        System.out.println("必要なパッケージがインポートされました");
        String input_string = "JVM";
        System.out.println("対象の文字列: " +input_string);
        ArrayList<String> string_list = SubString.split_string(input_string);
        System.out.println( "\nArrayListとして出力された部分文字列の一覧: ");
        System.out.println(string_list);
        System.out.println( "\n分割後の部分文字列: ");
        int count = 1;
        for (String it : string_list) {
            System.out.println("(" + count + ") \"" + it + "\"");
            count++;
        }
    }
}

実行結果

必要なパッケージがインポートされました
対象の文字列: JVM

ArrayListとして出力された部分文字列の一覧:
[J, JV, JVM, V, VM, M]

分割後の部分文字列:
(1) "J"
(2) "JV"
(3) "JVM"
(4) "V"
(5) "VM"
(6) "M"

まとめ

どちらの実装例でも、substring() メソッドと二重ループを組み合わせることで、文字列から取り出せるすべての部分文字列を効率的に列挙できます。文字列の長さを n とすると、部分文字列の総数は n(n+1)/2 個になります(上記の例では3文字なので 3×4÷2=6個)。処理をメソッドとして分離しておくと、他のプログラムからも呼び出せて便利なので、実務では例2のような関数化された書き方が推奨されます。

  1. Pythonで文字列を一意な部分文字列に分割したときの最大数を求める方法

    文字列 s が与えられたとき、その文字列を分割して得られる一意な部分文字列の最大数を見つける必要があります。文字列 s は、空でない部分文字列のリストに自由に分割でき、それらを連結すると元の文字列と一致しなければなりません。ただし、分割後のすべての部分文字列は互いに重複してはならず、すべて異なるものである必要があります。たとえば、入力が s = pqpqrrr の場合、出力は 5 になります。これは [p, q, pq, r, rr] のように分割できるためです。一方、[p, q, p, q, r, rr] のような分割は無効です。この場合、p と q が複数回現れているためです。解決アプロー

  2. Pythonでバイナリ文字列を「1」の数が等しい3つに分割する方法の数を求めるプログラム

    問題の概要バイナリ文字列 s が与えられたとき、これを3つの空でない文字列 s1、s2、s3 に分割することを考えます。このとき、s1 + s2 + s3 = s(連結)が成り立ち、かつ各部分文字列に含まれる 1 の個数がすべて等しくなるような分割方法の数を求めます。答えは非常に大きな値になる可能性があるため、10^9 + 7 で割った余りを返します。例えば、入力が s = 11101011 の場合、出力は 2 になります。「11 | 1010 | 11」と「11 | 101 | 011」の2通りの分割方法が存在するためです。解法のアプローチこの問題は、以下の手順で解くことができます。coun