この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:5
ページ更新者:T
更新日時:2026-06-11 07:07:02

タイトル: String.equalsIgnoreCase(大文字小文字を無視した等値比較)
SEOタイトル: Java String.equalsIgnoreCase の使い方と落とし穴(null 安全 / Locale / Unicode)

この記事の要点
  • equalsIgnoreCase = 大文字小文字を無視して文字列を比較。"HELLO".equalsIgnoreCase("hello") = true
  • equals との違い: equals は厳密一致、equalsIgnoreCase は ASCII の case 差を無視
  • null 安全には Objects.equals は不可(case を見ない)→ str != null && str.equalsIgnoreCase(other)
  • Locale 依存の比較はトルコ語の I 問題等で罠 → s.toLowerCase(Locale.ROOT).equals(...) が無難
  • Python の str.casefold() 比較や Java の String.compareToIgnoreCase も同系列

基本的な使い方

String a = "Hello";
String b = "HELLO";

a.equals(b);              // false — 大文字小文字が違う
a.equalsIgnoreCase(b);    // true  — 大文字小文字を無視

"java".equalsIgnoreCase("JAVA");  // true
"abc".equalsIgnoreCase("abcd");   // false — 長さ違い
"".equalsIgnoreCase("");          // true

// 数字や記号は通常通り比較
"123".equalsIgnoreCase("123");    // true
"a@b".equalsIgnoreCase("A@B");    // true

equals と equalsIgnoreCase の使い分け

場面推奨理由
パスワード比較equals大文字小文字も区別すべき
ID / トークン比較equals厳密一致が必要
メールアドレスequalsIgnoreCaseドメインは case 非依存(RFC)
ファイル拡張子equalsIgnoreCase.JPG と .jpg は同じ扱い
HTTP メソッドequalsIgnoreCasecase 非依存(RFC 7230)
列挙値("yes"/"no")equalsIgnoreCaseユーザ入力の揺れ吸収

null 安全な書き方

str.equalsIgnoreCase(null)false を返すので右辺は null OK。ただし左辺が null だと NPE:

String a = null;
String b = "HELLO";

// ❌ NullPointerException
// a.equalsIgnoreCase(b);

// ✅ null チェック
if (a != null && a.equalsIgnoreCase(b)) { ... }

// ✅ null を考慮した片方向比較
"HELLO".equalsIgnoreCase(a);  // false — null OK

// ✅ 定数を左に置く(Yoda 記法)
// 定数なら null にならないので NPE 起きない
"admin".equalsIgnoreCase(input);   // input が null でも false

// ❌ Objects.equals は使えない(大文字小文字を見ない)
Objects.equals("HELLO", "hello");  // false

// ✅ Objects 系で null セーフかつ ignore case
boolean eq = a == b ||
             (a != null && a.equalsIgnoreCase(b));

Locale の罠(トルコ語の I 問題)

標準 equalsIgnoreCaseLocale 非依存で安全ですが、toLowerCase() 経由の比較は危険:

import java.util.Locale;

// トルコ語ロケールだと "I".toLowerCase() == "ı" (ドットなし)
Locale tr = new Locale("tr", "TR");
"FILE".toLowerCase(tr);          // "fıle" ← ドットなし i!
"FILE".toLowerCase(tr).equals("file");  // false

// ❌ 危険: ユーザの Locale 依存
if ("ADMIN".toLowerCase().equals("admin")) { ... }

// ✅ 安全1: equalsIgnoreCase は内部で Locale 非依存比較
if ("ADMIN".equalsIgnoreCase("admin")) { ... }

// ✅ 安全2: Locale.ROOT 指定
if ("ADMIN".toLowerCase(Locale.ROOT).equals("admin")) { ... }

equalsIgnoreCase の内部実装

JDK 内部では1 文字ずつ Character.toUpperCase / toLowerCase で比較。サロゲートペアや特殊文字は完全対応ではないので、Unicode 厳密比較が必要なら Collator を使います:

import java.text.Collator;

Collator collator = Collator.getInstance(Locale.JAPANESE);
collator.setStrength(Collator.SECONDARY);  // case 無視

collator.compare("ABC", "abc") == 0;       // true
collator.compare("ハンカク", "ハンカク") == 0;  // 半角全角同一視(要 Strength 設定)

// 大量比較は CollationKey でキャッシュ
CollationKey k1 = collator.getCollationKey("Apple");
CollationKey k2 = collator.getCollationKey("apple");
k1.compareTo(k2) == 0;   // true

compareToIgnoreCase(順序比較)

// 等値だけでなく順序が欲しいとき
"apple".compareToIgnoreCase("BANANA");   // 負(apple < banana)

// ソート
List list = Arrays.asList("Banana", "apple", "Cherry");
list.sort(String.CASE_INSENSITIVE_ORDER);
// [apple, Banana, Cherry]

// Comparator
Comparator c = Comparator.comparing(String::toLowerCase);
list.sort(c);

他言語の同等機能

言語記法備考
Javaa.equalsIgnoreCase(b)Locale 非依存
Kotlina.equals(b, ignoreCase = true)標準ライブラリ
C#string.Equals(a, b, StringComparison.OrdinalIgnoreCase)Ordinal が安全
JavaScripta.toLowerCase() === b.toLowerCase()locale-aware なら localeCompare
Pythona.casefold() == b.casefold()Unicode 厳密
PHPstrcasecmp($a, $b) === 0マルチバイトは mb_strtolower

Unicode 厳密比較(casefold 相当)

// Java には casefold ピッタリは無い。Normalizer + toLowerCase
import java.text.Normalizer;

static String foldCase(String s) {
    return Normalizer.normalize(s, Normalizer.Form.NFKC)
                     .toLowerCase(Locale.ROOT);
}

foldCase("file").equals(foldCase("FILE"));   // true (合字fi→fi)
foldCase("Ⅷ").equals(foldCase("VIII"));    // true (ローマ数字)

FAQ

Q: equalsIgnoreCase で日本語の比較は?
A: ひらがな・カタカナ・漢字には case 概念が無いので equals と同じ動作。半角全角の区別は残る。

Q: 高速化したい
A: ハッシュマップに入れるなら key.toLowerCase(Locale.ROOT) で正規化してから格納。比較毎の toLowerCase 呼び出しを避ける。

Q: equalsIgnoreCase は Unicode 完全対応?
A: 基本対応だが、サロゲートペアや特殊な合字は厳密ではない。Unicode 仕様準拠が必要なら ICU4J の UCharacter.foldCase