Javaについて徹底解説!

文字・文字列の位置を調べる、String.indexOf/lastIndexOfの使い方

大石 英人

開発エンジニア/Java20年/Java GOLD/リーダー/ボールド歴2年

String.indexOf/lastIndexOfは、指定した文字・文字列がString中に出現する位置(インデックス)を戻すメソッドです。Javaでの文字列操作では基本の一つですので、しっかり覚えましょう。

この記事では、String.indexOf/lastIndexOfの使い方から、簡単な応用までを初心者向けにお伝えします。

※この記事のサンプルは、Java 10の環境で動作確認しています。


1.String.indexOf/lastIndexOfの使い方

1-1.Stringのインデックスとは文字単位の位置

ここでString.indexOf/lastIndexOfを使うために必要な、Stringのインデックスの考え方をまず覚えましょう。Stringのインデックスとは、文字列中に含まれる文字に順番に割り当てられた数字です。

文字列の最初の文字がインデックス 0 で、順番に+1されます。これは配列の添え字と同じルールです。ですので、最後の文字のインデックスは、String.length()より1少ない数になります。

String str = "あいうえお";

// 文字列をインデックスと一緒に表示
for (int i = 0; i < str.length(); i++) {
	System.out.println(String.format("strのインデックス %d は %s です。", i, str.charAt(i)));
}

※出力結果:
strのインデックス 0 は あ です。
strのインデックス 1 は い です。
strのインデックス 2 は う です。
strのインデックス 3 は え です。
strのインデックス 4 は お です。

Stringのインデックスの考え方はこれだ!

なお、JavaではStringを使う場合は文字数でインデックスを指定します。他のプログラミング言語でShift_JISなどを扱う時とは違い、各文字のbyte数は意識しなくてもよいので、いわゆる全角・半角の文字種判断結果による調整も不要です。

1-2.String.indexOfは文字・文字列を前から探す

では、String.indexOfから見ていきましょう。indexOfは、Stringが持つ文字列の前から、指定した文字・文字列が出現するインデックスを戻すメソッドです。

戻り値としては、文字・文字列がString中にある場合はそのインデックスが戻ります。文字・文字列がない場合は-1が戻ります。

indexOfの基本形は、以下の2つのメソッドです。これらは探すものが文字一つだけか、あるいは文字列かが違っています。

public int indexOf(int ch)
	ch - 文字(Unicodeコード・ポイント)。
public int indexOf(String str)
	str - 検索対象の部分文字列。
String str = "あいうえお"; // 0:あ 1:い 2:う 3:え 4:お
System.out.println(str.indexOf('う')); // → 2
System.out.println(str.indexOf("う")); // → 2
System.out.println(str.indexOf("えお")); // → 3
System.out.println(str.indexOf('か')); // → -1、'か'はstr中に存在しない
System.out.println(str.indexOf("か")); // → -1、"か"はstr中に存在しない
System.out.println(str.indexOf("あお")); // → -1、"あお"はstr中に存在しない

indexOfのバリエーションとして、文字・文字列を探し始めるインデックスを2つ目の引数で指定できるものがあります。先ほど紹介したものは、これに0が設定されているものと考えればわかりやすいでしょう。

public int indexOf(int ch, int fromIndex)
	ch - 文字(Unicodeコード・ポイント)。
	fromIndex - 検索開始位置のインデックス。
public int indexOf(String str, int fromIndex)
	str - 検索対象の部分文字列。
	fromIndex -検索開始位置のインデックス。
//  0:あ  1:い  2:う  3:え  4:お
//  5:か  6:き  7:く  8:け  9:こ
// 10:あ 11:い 12:う 13:え 14:お
String str = "あいうえおかきくけこあいうえお";
System.out.println(str.indexOf('う', 0)); // → 2
System.out.println(str.indexOf("う", 0)); // → 2
System.out.println(str.indexOf('う', 4)); // → 12
System.out.println(str.indexOf("う", 4)); // → 12
System.out.println(str.indexOf("えお", 4)); // → 13

1-3.String.lastIndexOfは文字・文字列を後ろから探す

String.indexOfは前から探すものでしたが、lastIndexOfは後ろから探します。これもindexOfと同様に、文字・文字列の違いと、探し始めるインデックスの違いで以下の4種類があります。戻り値も、見つかったインデックスが戻り、見つからなかった場合は-1が戻ります。

public int lastIndexOf(int ch)
	ch - 文字(Unicodeコード・ポイント)。
public int lastIndexOf(int ch, int fromIndex)
	ch - 文字(Unicodeコード・ポイント)。
	fromIndex - 検索開始位置のインデックス。 
public int lastIndexOf(String str)
	str - 検索対象の部分文字列。
public int lastIndexOf(String str, int fromIndex)
	str - 検索対象の部分文字列。
	fromIndex - 検索開始位置のインデックス。

以下の例で、後ろから探し始めるということと、探し始めるインデックスがどう影響するかがお分かりになるかと思います。開始インデックスが未指定のものは、一番最後のインデックスが指定されていると考えてください。

//  0:あ  1:い  2:う  3:え  4:お
//  5:か  6:き  7:く  8:け  9:こ
// 10:あ 11:い 12:う 13:え 14:お
String str = "あいうえおかきくけこあいうえお";
System.out.println(str.lastIndexOf('う')); // → 12、一番後ろから探しているため
System.out.println(str.lastIndexOf("う")); // → 12
System.out.println(str.lastIndexOf('う', 4)); // → 2、インデックス4(=最初の"お")から前を探しているため
System.out.println(str.lastIndexOf("う", 4)); // → 2

1-4.探す文字は大文字・小文字かどうかに気を付けよう

JavaはString中に含まれる文字の大文字・小文字を区別します。indexOf/lastIndexOfも同様に大文字小文字を区別しますので、探したい文字列が見つからない場合があります。

String str = "aBcDeFg";
System.out.println(str.indexOf('C')); // → -1、大文字のcは含まれていないため
System.out.println(str.indexOf('c')); // → 2

文字列を探す時に大文字・小文字を区別したくないなら、String.toUpperCase/toLowerCaseやCharacter/toUpperCase・toLowerCaseを使って、比較先・元の文字列を大文字か小文字のどちらかに変換して統一しましょう。変換は比較元・先の両方で行うとより確実です。

String str = "aBcDeFg";

String str1 = str.toLowerCase();
char c1 = Character.toLowerCase('C');
System.out.println(str1); // → abcdefg
System.out.println(c1); // → c
System.out.println(str1.indexOf(c1)); // → 2
System.out.println(str1.indexOf('c')); // → 2
System.out.println(str1.indexOf('C')); // → -1

String str2 = str.toUpperCase();
char c2 = Character.toUpperCase('c');
System.out.println(str2); // → ABCDEFG
System.out.println(c2); // → C
System.out.println(str2.indexOf(c2)); // → 2
System.out.println(str2.indexOf('c')); // → -1
System.out.println(str2.indexOf('C')); // → 2

なお、toUpperCase/toLowerCaseを行っても元のStringの内容は変わりませんので、indexOfで取得したインデックスはそのまま使えます。

String str = "aBcDeFg";
String str1 = str.toLowerCase();
System.out.println(str); // → aBcDeFg
System.out.println(str1); // → abcdefg

1-5.文字列の有無を知るならString.containsも使おう

前述のとおり、indexOfではString中に探したい文字・文字列がなかった場合は-1が戻るので、文字・文字列の有無を調べるのにも使えます。その際、String.containsを使えば、ある・ないをbooleanで得られるので、プログラムをより分かりやすくできます。

public boolean contains(CharSequence s)
String str = "ABCDEFG";

System.out.println(str.indexOf("C")); // → 2
System.out.println(str.indexOf("あ")); // → -1
System.out.println(str.contains("C")); // → true
System.out.println(str.contains("あ")); // → false

if (str.indexOf("E") != -1) {
	System.out.println("Eは含まれています。");
} else {
	System.out.println("Eは含まれていません。");
}

if (str.contains("E")) {
	System.out.println("Eは含まれています。");
} else {
	System.out.println("Eは含まれていません。");
}

ただし、containsは開始位置が0indexOfと同じ動きをするので、開始インデックスは指定できません。また、文字用のメソッドがありません。それらの制限があるならindexOfを使いましょう。


2.【応用】String.substringとの組み合わせ

indexOf/lastIndexOfはそれだけだと使い道があまりありません。最も普通の使い方はString.substringとの組み合わせです。substringStringから部分文字列を切り出すメソッドで、このインデックスとしてindexOf/lastIndexOfの戻り値を使うのです。

public String substring(int beginIndex)
	beginIndex - 開始インデックス(この値を含む)。
public String substring(int beginIndex, int endIndex)
	beginIndex - 開始インデックス(この値を含む)。
	endIndex - 終了インデックス(この値を含まない)。

例えば、String中からとある文字列を探し、そこから後ろのすべての文字列を取得したりできます。このように、indexOf/lastIndexOfsubstringは使い勝手がいいようになっています。

// "うえ"から後ろの文字列をすべて取得する
String str = "あいうえお";
int index = str.indexOf("うえ");
String substr = str.substring(index);
System.out.println(substr); // → うえお
// "え"から"け"までにある文字列をすべて取得する
String str = "あいうえおかきくけこ";
int beginIndex = str.indexOf("え");
int endIndex = str.indexOf("け");
String substr = str.substring(beginIndex, endIndex);
System.out.println(substr); // → えおかきく

3.【応用】String.indexOf/lastIndexOfの活用例

3-1.ファイル拡張子、ファイル名部分の取得

String.substring()とString.lastIndexOf()の例として、ファイルの拡張子を得る際に使えます。拡張子を除く部分が必要な場合も同じ考え方です。

String fileName = "FILE.NAME.txt";
int endIndex = fileName.lastIndexOf('.'); // 最後の'.'のインデックスを検索
String extName = fileName.substring(endIndex + 1); // → "txt"、一番最後の'.'から後ろの文字列を全て取得
String baseName = fileName.substring(0, endIndex); // → "FILE.NAME"、先頭から一番最後の'.'の前までの部分文字列

ファイルのパスからファイル名だけ抜き出したい場合も考え方は同じです。区切り文字を変えるだけですね。

String pathName = "/A/B/FILE.NAME.txt";
int endIndex = pathName.lastIndexOf('/'); // 最後の'/'のインデックスを検索
String fileName = pathName.substring(endIndex + 1); // → "FILE.NAME.txt"

3-2.「パラメータ名=値」の分解

例えば、何かの設定ファイルに“ABC=123”とあった場合に、“=”の左側の変数名と右側の値をそれぞれ取り出したいとします。Javaの場合、やり方は色々ありますが、indexOfを使うなら以下のようになります。

String str = "ABC=123";
String separator = "=";
int index = str.indexOf(separator);
String name = str.substring(0, index); // インデックスの前までが名前
String value = str.substring(index + separator.length()); // インデックスの後ろからが値
System.out.println("name→" + name);
System.out.println("value→" + value);

似たような用途に使えるString.splitだと、引数に気を付けないと値側に“=”が含まれていた場合にも分解されてしまいます。分解したいのは「最初に」出現する“=”の左右だけで、右側にある値はそのまま欲しいのです。このような用途にはindexOfを使うとシンプルにできます。

String str = "ABC=123=456";
String[] strArr = str.split("=");
System.out.println(Arrays.toString(strArr)); // → [ABC, 123, 456]

// ただし、limit付のsplitなら大丈夫!!
String[] strArr2 = str.split("=", 2);
System.out.println(Arrays.toString(strArr2)); // → [ABC, 123=456]

3-3.CSVの分解

CSV(comma-separated values)などの、特定の区切り文字で連結した文字列から、各要素を抜き出す時にもString.indexOf()は使えます。簡単に行うならString.splitでいいのですが、区切り文字が“”で囲まれている場合など単純に処理出来ない場合もあるので、これをベースに拡張したりします。

String csvStr = "A,あいうえお,,C,1234";
List<String> csvElements = new ArrayList<>();
int beginIndex = 0;

while (true) {
	int endIndex = csvStr.indexOf(',', beginIndex);

	if (endIndex == -1) {
		csvElements.add(csvStr.substring(beginIndex));
		break;
	} else {
		csvElements.add(csvStr.substring(beginIndex, endIndex));
		beginIndex = endIndex + 1;
	}
}

4.【参考】StringBuilder/StringBufferのindexOf/lastIndexOf

Stringを作る際はStringBuilder/StringBufferを使うことが多いと思います。これらもString版のみですがindexOf/lastIndexOfを持っていますので、Stringを作っている最中にもStringBuilder/StringBuffer内に文字・文字列があるかどうかを調べられます。

StringBuilder sb = new StringBuilder("あいうえお");
System.out.println(sb.indexOf("う")); // → 2
System.out.println(sb.indexOf("か")); // → -1
System.out.println(sb.lastIndexOf("え")); // → 3
System.out.println(sb.lastIndexOf("か")); // → -1

ちなみに、substringもStringと同じように使えますので、ほぼStringと同じようにを扱えるのですね。

StringBuilder sb = new StringBuilder("あいうえお");
int index = sb.indexOf("う");
String substr = sb.substring(index, index + 2);
System.out.println(substr); // → うえ
String substr2 = sb.substring(index);
System.out.println(substr2); // → うえお

5.まとめ

String.indexOf/lastIndexOfは、Stringから指定した文字・文字列が出現するインデックスを得るのに使います。先頭から探すにはindexOf、最後から探すにはlastIndexOfです。さらに、探し始めるインデックスを指定できるメソッドもあります。

String.indexOf/lastIndexOfを使う際は、大抵String.substringとセットになります。indexOf/lastIndexOfで探している文字・文字列のインデックスを探し、substringで切り出す…が良く見られるものです。

indexOf/lastIndexOfはそれだけでは単純な機能しかありませんが、他のメソッドと組み合わせることで文字列の色々な解析に使えます。基本をしっかり覚えて、便利に使いましょう!

私たちは、全てのエンジニアに市場価値を高め自身の望む理想のキャリアを歩んでいただきたいと考えています。もし、今あなたが転職を検討しているのであればこちらの記事をご一読ください。理想のキャリアを実現するためのヒントが見つかるはずです。

『技術力』と『人間力』を高め市場価値の高いエンジニアを目指しませんか?

私たちは「技術力」だけでなく「人間力」の向上をもって遙かに高い水準の成果を出し、関わる全ての人々に感動を与え続ける集団でありたいと考えています。

高い水準で仕事を進めていただくためにも、弊社では次のような環境を用意しています。

  • 定年までIT業界で働くためのスキル(技術力、人間力)が身につく支援
  • 「給与が上がらない」を解消する6ヶ月に1度の明確な人事評価制度
  • 平均残業時間17時間!毎週の稼動確認を徹底しているから実現できる働きやすい環境

現在、株式会社ボールドでは「キャリア採用」のエントリーを受付中です。

まずは以下のボタンより弊社の紹介をご覧いただき、あなたの望むキャリアビジョンをエントリーフォームより詳しくお聞かせください。

コメント

文系IT未経験歓迎!【23卒対象】新卒採用のエントリーを受付中!
文系IT未経験歓迎!
【23卒対象】新卒採用のエントリーを受付中!