Java道|indexOfで文字の位置を調べる

文字がどこにあるか分かると、文字列処理はもっと賢くなる。
indexOf() は、巻物の中から目的の文字を探し出す基本技。

Javaで文字列を扱っていると、「この文字はどこにあるのか」「この記号は含まれているのか」を調べたい場面がよくあります。

たとえば、メールアドレス風の文字列に @ が入っているかを確認したいときがあります。
また、文章の中に特定の文字や言葉が含まれているかを調べたいこともあります。

こうした文字列検索で役立つのが、String クラスの indexOf() メソッドです。

indexOf() は、指定した文字や文字列が、対象の文字列の中で最初に現れる位置を返すメソッドです。
見つかった場合は、その位置を int 型の数値で返します。
見つからなかった場合は、-1 を返します。

鬼滅の刃でたとえると、文字列は任務内容が書かれた巻物です。
indexOf() は、その巻物の中から「指定された印」や「合図の文字」がどこに書かれているかを探す技です。

ただ読むだけではなく、どこにあるかを数値で教えてくれるところがポイントです。

この indexOf() を理解すると、文字列の中身を調べて、見つかった場合と見つからなかった場合で処理を分けられるようになります。
入力チェックや検索処理にもつながる、とても大切な基本です。

文字の位置を探すとはどういうことか

文字列は、文字が順番に並んだデータです。

たとえば、たんぽぽ という文字列を考えてみましょう。

Javaでは、文字の位置を 0 から数えます。

位置文字
0
1
2
3

日常の言い方では、た は1文字目、ん は2文字目、最初の ぽ は3文字目、次の ぽ は4文字目です。

しかし、Javaの位置番号では、先頭の た が 0 です。

このため、たんぽぽ の中で最初に ぽ が見つかる位置は 2 になります。

探す文字Javaで返る位置人が数える言い方
01文字目
12文字目
23文字目

鬼滅の刃でたとえると、任務の巻物に文字ごとの札番号がふられていて、その札番号が 0 から始まっているようなものです。

indexOf() は、その札番号を探して返してくれる技だと考えると分かりやすいです。

indexOf()メソッドの役割

indexOf() は、指定した文字や文字列を検索し、最初に見つかった位置を返すメソッドです。

基本の形は次のようになります。

文字列変数.indexOf(探したい文字)

または、文字列を探すこともできます。

文字列変数.indexOf(探したい文字列)

戻り値は int 型です。
つまり、検索結果の位置を整数で受け取ります。

結果返される値
見つかった場合最初に現れた位置
見つからなかった場合-1

この -1 がとても大切です。

Javaでは、文字の位置は 0 から始まります。
つまり、0 は「先頭で見つかった」という意味です。

そのため、「見つからなかった」を表す値として 0 は使えません。
そこで indexOf() は、見つからなかった場合に -1 を返します。

indexOf() の結果意味
0先頭で見つかった
1以上途中で見つかった
-1見つからなかった

鬼滅の刃でたとえると、巻物に探している印があれば、その札番号を返します。
どこにも印がなければ、「存在しない」という合図として -1 を返すイメージです。

indexOf() の動きを確認する

実際のプログラムで indexOf() の動きを見てみましょう。

ファイル名:Sample3.java

import java.io.*;

class Sample3
{
    public static void main(String[] args) throws IOException
    {
        // キーボード入力の準備をする
        BufferedReader br =
            new BufferedReader(new InputStreamReader(System.in));

        // 検索される文字列を入力してもらう
        System.out.println("任務の言葉を入力してください。");
        String str1 = br.readLine();

        // 探したい文字を入力してもらう
        System.out.println("探したい1文字を入力してください。");
        String str2 = br.readLine();

        // 入力された先頭の1文字を取り出す
        char ch = str2.charAt(0);

        // 文字の位置を検索する
        int num = str1.indexOf(ch);

        // 結果を表示する
        if (num != -1)
            System.out.println(str1 + "の" + (num + 1) + "文字目に「" + ch + "」が見つかりました。");
        else
            System.out.println(str1 + "の中に「" + ch + "」は見つかりませんでした。");
    }
}

このプログラムでは、まず検索される文字列を入力します。
次に、探したい1文字を入力します。

そのあとで、charAt(0) を使って、入力された文字列の先頭1文字を取り出しています。

char ch = str2.charAt(0);

そして、indexOf() を使って、その文字が str1 の中のどこにあるかを調べます。

int num = str1.indexOf(ch);

見つかった場合は位置が num に入ります。
見つからなかった場合は -1 が入ります。

たとえば、次のように入力したとします。

任務の言葉を入力してください。
たんぽぽ
探したい1文字を入力してください。
ぽ

この場合、たんぽぽ の中で最初に ぽ が見つかる Java上の位置は 2 です。

ただし、表示では num + 1 を使って、人が読みやすい 3文字目 として表示します。

たんぽぽの3文字目に「ぽ」が見つかりました。

鬼滅の刃でたとえると、たんぽぽ と書かれた任務の巻物から ぽ という印を探し、最初に見つかった場所を報告している流れです。

プログラムの流れを順番に整理する

Sample3.java の処理の流れを順番に見てみましょう。

順番処理説明
1BufferedReader を作るキーボード入力の準備をする
2str1 に文字列を入力する検索される対象の文字列を受け取る
3str2 に探したい文字を入力する探したい内容を文字列として受け取る
4str2.charAt(0)入力された先頭の1文字を取り出す
5str1.indexOf(ch)str1 の中から ch を探す
6if 文で判定する見つかった場合と見つからなかった場合で表示を分ける

この流れを見ると、indexOf() だけで処理が完成しているわけではないことが分かります。

入力には BufferedReader を使っています。
1文字を取り出すために charAt() を使っています。
見つかったかどうかを判断するために if 文を使っています。

文字列処理では、このように複数の基本を組み合わせることがとても多いです。

鬼滅の刃でたとえると、任務の巻物を受け取り、探す印を確認し、巻物の中を調べ、見つかったかどうかを報告する一連の任務です。

charAt(0)を使っている理由

Sample3.java では、探したい文字を次のように入力しています。

String str2 = br.readLine();

br.readLine() は、キーボードから入力された1行分を String 型として返します。

つまり、ユーザーが ぽ と1文字だけ入力しても、str2 は char 型ではなく String 型です。

そこで、先頭の1文字を取り出すために charAt(0) を使います。

char ch = str2.charAt(0);
処理意味
br.readLine()入力を String として受け取る
str2.charAt(0)受け取った文字列の先頭1文字を取り出す
char ch取り出した1文字を char 型で保存する

鬼滅の刃でたとえると、隊士が「ぽ」と書いた小さな巻物を渡してきたとします。
その巻物そのものは文字列ですが、その中の先頭に書かれた1文字だけを取り出して、検索用の印として使っているイメージです。

なお、indexOf() は char だけでなく String も探せます。
ただし、今回のプログラムでは「探したい1文字」を扱う形にしているため、charAt(0) で1文字を取り出しています。

indexOf()は最初に見つかった位置を返す

indexOf() の重要なポイントは、最初に見つかった位置を返すことです。

たとえば、文字列 こころここにあり の中で こ を探す場合を考えます。

位置文字
0
1
2
3
4
5
6
7

この文字列には こ が何回も出てきます。

しかし、indexOf('こ') の結果は 0 です。

なぜなら、一番最初に見つかった こ の位置を返すからです。

探す文字最初に見つかる位置
0
2
5

鬼滅の刃でたとえると、巻物の中に同じ印が何度も出てきたとしても、indexOf() は最初に見つけた印の札番号だけを報告する技です。

2回目以降の位置を探したい場合は、別の使い方や別のメソッドも学んでいく必要があります。
まずは、indexOf() は最初の一致を返す、と押さえておきましょう。

見つからないときは-1が返る

indexOf() では、探した文字が見つからないこともあります。

たとえば、すいか という文字列の中で め を探したとします。

位置文字
0
1
2

この中に め はありません。

そのため、indexOf('め') の結果は -1 になります。

indexOf() の結果意味
0以上見つかった
-1見つからなかった

Sample3.java では、このルールを使って if 文で分岐しています。

if (num != -1)
    System.out.println(str1 + "の" + (num + 1) + "文字目に「" + ch + "」が見つかりました。");
else
    System.out.println(str1 + "の中に「" + ch + "」は見つかりませんでした。");

num != -1 は、「見つかった場合」という意味です。

条件意味
num != -1見つかった
num == -1見つからなかった

ここで注意したいのは、見つからなかった値が 0 ではないことです。

0 は先頭で見つかったという意味です。
そのため、0 を見つからない意味として扱うと、先頭にある文字を正しく判定できなくなります。

鬼滅の刃でたとえると、0番札に印がある場合もあります。
だから、「印がない」という合図には、札番号として使われない -1 が使われるのです。

なぜnum + 1として表示しているのか

Sample3.java の表示部分では、num をそのまま表示していません。

System.out.println(str1 + "の" + (num + 1) + "文字目に「" + ch + "」が見つかりました。");

ここで num + 1 を使っています。

理由は、Javaの位置番号と、人が普段数える文字数の言い方が違うからです。

Javaでは、先頭の位置が 0 です。
しかし、人に説明するときは、先頭を 1文字目 と言うほうが自然です。

たとえば、たんぽぽ で最初の ぽ が見つかる位置は、Javaでは 2 です。

Javaでの位置人がふつうに数える位置文字
01文字目
12文字目
23文字目
34文字目

そのため、表示するときは num + 1 にして、3文字目 と出しています。

用途使う値
プログラム内部で位置として使うnum
人に見せる表示num + 1

鬼滅の刃でたとえると、鬼殺隊の内部管理では札番号 0 から数えます。
でも、報告書では人が分かりやすいように 1文字目、2文字目 と書き直しているようなものです。

indexOf()のイメージを図でつかむ

↓クリックすると拡大表示されます。

この図が示していること

この図では、文字列 たんぽぽ の中から ぽ を探す流れを表しています。

たんぽぽ の文字には、Javaで使う位置番号として 0、1、2、3 がついています。
indexOf('ぽ') は、最初に見つかった ぽ の位置である 2 を返します。

ただし、人に表示するときは 3文字目 と言うほうが自然なので、num + 1 にして表示します。

ここから分かるのは、indexOf() は文字そのものを返すのではなく、見つかった位置を返すメソッドだということです。
また、Javaの位置番号は 0 から始まるため、表示用には調整が必要になることも分かります。

indexOf()を使うとどんな場面で便利なのか

indexOf() は、学習用だけでなく、実際のプログラムでもよく使われます。

文字列の中に特定の文字や記号が含まれているかを調べられるからです。

場面使い方のイメージ
メールアドレス風の文字列を確認する@ が含まれているかを調べる
ファイル名を確認する. がどこにあるかを探す
文章の検索特定の語句が含まれているか調べる
区切り位置の発見ハイフンやスラッシュの位置を見つける
入力チェック必要な記号が入っているか確認する

たとえば、メールアドレス風の文字列で @ が入っているかを調べたい場合、indexOf("@") の結果が -1 でなければ、@ が含まれていると判断できます。

鬼滅の刃でたとえると、任務の巻物に「合図の印」や「区切りの印」が書かれているかを確認する場面です。
印がどこにあるか分かれば、その前後を切り分けたり、正しい形式かを判断したりできます。

文字だけでなく文字列も検索できる

今回の Sample3.java では、1文字を検索しています。

int num = str1.indexOf(ch);

この場合、ch は char 型です。

ただし、indexOf() は1文字だけでなく、文字列も検索できます。

たとえば、次のような使い方です。

String text = "藤の森へ向かう";
int num = text.indexOf("森");

この場合、森 が最初に現れる位置を返します。

さらに、複数文字の文字列も探せます。

String text = "東京タワー";
int num = text.indexOf("タワ");

この場合、タワ が始まる位置が返されます。

書き方検索対象
indexOf(char)1文字を探す
indexOf(String)文字列を探す

鬼滅の刃でたとえると、1文字の印を探すこともできますし、「藤の森」のようなまとまった言葉を探すこともできます。

indexOf() は、1文字検索にも部分文字列検索にも使える便利なメソッドです。

見つかった位置を使って次の処理につなげられる

indexOf() の便利なところは、単に見つかったかどうかを調べるだけではありません。

見つかった位置を使って、次の処理につなげられるところです。

たとえば、文字列の中に区切り記号がある場合、その位置を indexOf() で探し、その前後を切り分ける処理に発展できます。

処理使うメソッド
記号の位置を探すindexOf()
その位置より前を取り出すsubstring()
その位置より後ろを取り出すsubstring()

たとえば、任務コード A-100 の中で - の位置を探せば、A と 100 に分けることもできます。

鬼滅の刃でたとえると、巻物の中にある区切りの印を見つけ、その前を任務種別、後ろを任務番号として読み分けるようなものです。

このように、indexOf() は、substring() などの他の String メソッドと組み合わせることで、さらに実用的になります。

図:見つからないときは-1を返す

↓クリックすると拡大表示されます。

この図が示していること

この図では、indexOf() で文字が見つかった場合と、見つからなかった場合を比較しています。

左側では、さくらもち の中から も を探しています。
も は Java上の位置 3 にあるため、indexOf('も') の結果は 3 です。

右側では、すいか の中から め を探しています。
め は含まれていないため、indexOf('め') の結果は -1 です。

ここから分かるのは、indexOf() は見つかったら位置を返し、見つからなかったら -1 を返すということです。
また、0 は「見つからない」ではなく、「先頭で見つかった」という意味なので、-1 と区別する必要があります。

よくある注意点

indexOf() を使うときは、いくつか注意したいポイントがあります。

注意点内容
位置は 0 から始まる1文字目は位置 0
見つからないと -10 ではないので注意する
最初に見つかった位置を返す同じ文字が複数あっても最初の位置
戻り値は int見つかった文字ではなく位置が返る
charAt(0) と組み合わせることがある入力文字列から1文字を取り出すため
文字列も検索できるindexOf(String) で部分文字列を探せる

特に大切なのは、見つからないときの -1 です。

0 は先頭で見つかったという意味です。
見つからないという意味ではありません。

結果正しい意味
0先頭で見つかった
-1見つからなかった

鬼滅の刃でたとえると、0番札に印があることもあります。
だから、印がない場合は 0 ではなく、特別な合図として -1 を使うのです。

今後の文字列処理につながる大事な一歩

indexOf() を理解すると、文字列をただ表示するだけでなく、中身を調べて判断できるようになります。

これは、この先に学ぶ substring()、startsWith()、endsWith() などのメソッドにもつながる大切な考え方です。

今後の文字列処理indexOf() とのつながり
substring()見つかった位置をもとに一部分を切り出す
startsWith()先頭に特定の文字列があるか調べる
endsWith()末尾に特定の文字列があるか調べる
入力チェック必要な記号が含まれているか判定する
検索処理特定の語句が含まれるか調べる

鬼滅の刃でたとえると、indexOf() は巻物の中から印の位置を探す基本技です。

印の位置が分かれば、その前後を読み分けたり、任務内容が正しい形式か確認したりできます。

文字列の中に何があるのか。
それはどこにあるのか。
見つからなかった場合はどう判断するのか。

この感覚が身につくと、Javaの文字列処理はかなり扱いやすくなります。