部分一致は「含まれているかどうか」を調べる基本テクニック
業務システムで「部分一致」はめちゃくちゃよく出てきます。
商品名に「りんご」が含まれているデータだけ検索したい。
エラーメッセージに特定のキーワードが含まれているかで処理を分けたい。
ログの1行の中に「ERROR」が入っているかをチェックしたい。
こういうときに使うのが「部分一致」です。
ざっくり言うと「ある文字列の中に、別の文字列が含まれているかどうか」を調べる処理です。
Javaでは、これをユーティリティメソッドとしてまとめておくと、あちこちで再利用できてコードがかなりスッキリします。
Javaの基本メソッドで部分一致を押さえる
containsで「含まれているか」をシンプルに判定する
一番基本になるのは String#contains です。
「この文字列の中に、指定した文字列が含まれているか」を true/false で返してくれます。
public final class StringMatchUtil {
private StringMatchUtil() {}
public static boolean contains(String text, String keyword) {
if (text == null || keyword == null) {
return false;
}
return text.contains(keyword);
}
}
Java使い方はとてもシンプルです。
System.out.println(StringMatchUtil.contains("りんごジュース", "りんご")); // true
System.out.println(StringMatchUtil.contains("みかんジュース", "りんご")); // false
System.out.println(StringMatchUtil.contains("ERROR: something wrong", "ERROR")); // true
System.out.println(StringMatchUtil.contains("INFO: ok", "ERROR")); // false
Javaここでまず大事なのは、「null をどう扱うかを決める」ことです。
上の実装では、text か keyword のどちらかが null なら false を返す、という方針にしています。
「null は一致しないものとして扱う」というルールを決めておくと、呼び出し側のコードが安定します。
indexOfで「どこに含まれているか」も知る
contains は true/false だけですが、
「どの位置に含まれているか」を知りたいときは indexOf を使います。
public static int indexOf(String text, String keyword) {
if (text == null || keyword == null) {
return -1;
}
return text.indexOf(keyword); // 見つからなければ -1
}
JavaSystem.out.println(indexOf("りんごジュース", "りんご")); // 0
System.out.println(indexOf("おいしいりんごジュース", "りんご")); // 4
System.out.println(indexOf("みかんジュース", "りんご")); // -1
JavaindexOf は「見つからなければ -1」という約束になっているので、
「0以上なら含まれている」「-1なら含まれていない」と判定できます。
位置が必要ない場面では contains、位置も使いたい場面では indexOf、という使い分けを覚えておくと便利です。
前方一致・後方一致も「部分一致の仲間」として押さえる
startsWithで「この文字列で始まっているか」を判定する
「部分一致」の一種として、前方一致(前から一致)もよく使います。
Javaでは startsWith で判定できます。
public static boolean startsWith(String text, String prefix) {
if (text == null || prefix == null) {
return false;
}
return text.startsWith(prefix);
}
JavaSystem.out.println(startsWith("ABC123", "ABC")); // true
System.out.println(startsWith("XYZ123", "ABC")); // false
Java例えば「商品コードが ‘ABC’ で始まるものだけ抽出したい」といった場面で使えます。
endsWithで「この文字列で終わっているか」を判定する
同じように、後方一致(後ろから一致)は endsWith です。
public static boolean endsWith(String text, String suffix) {
if (text == null || suffix == null) {
return false;
}
return text.endsWith(suffix);
}
JavaSystem.out.println(endsWith("report.csv", ".csv")); // true
System.out.println(endsWith("image.png", ".csv")); // false
Javaファイル拡張子のチェックや、特定のサフィックスを持つIDの判定など、実務でかなり出番があります。
大文字小文字を無視した部分一致
toLowerCase / toUpperCase で正規化してから比較する
英字を扱うときに必ず出てくるのが「大文字小文字を区別するかどうか」です。
例えば "Error" も "ERROR" も "error" も、全部「エラー」として扱いたい、というケースはよくあります。
その場合は、両方を同じ大文字・小文字に揃えてから contains すればOKです。
public static boolean containsIgnoreCase(String text, String keyword) {
if (text == null || keyword == null) {
return false;
}
String t = text.toLowerCase();
String k = keyword.toLowerCase();
return t.contains(k);
}
JavaSystem.out.println(containsIgnoreCase("ERROR: something", "error")); // true
System.out.println(containsIgnoreCase("Error: something", "ERROR")); // true
System.out.println(containsIgnoreCase("Info: ok", "ERROR")); // false
Javaここで深掘りしたいのは「正規化(normalize)」という考え方です。
判定ロジックそのものは contains と同じですが、その前に
すべて小文字にする(または大文字にする)
という前処理を挟んでいます。
この「前処理+本処理」という分け方は、部分一致に限らず、
文字列処理全般でとても重要なパターンです。
全角・半角や空白をどう扱うかを決める
「見た目として一致していればOK」にしたい場合
日本語のシステムでは、「全角・半角」「全角スペース・半角スペース」が絡んできます。
例えば、ユーザーが「 りんご」(先頭に全角スペース)と入力しても、
「りんご」と一致したとみなしたい、ということがあります。
その場合も、やることは「正規化してから部分一致」です。
簡単な例として、「前後の空白を削る」「全角英数字を半角にする」などを行ってから contains します。
public static String normalizeSimple(String text) {
if (text == null) {
return null;
}
String trimmed = text.trim(); // 前後の空白を削る(全角スペースは別途対応が必要な場合も)
// ここで本格的な全角→半角変換をするなら、外部ライブラリや自前実装が必要
return trimmed;
}
public static boolean containsNormalized(String text, String keyword) {
if (text == null || keyword == null) {
return false;
}
String t = normalizeSimple(text);
String k = normalizeSimple(keyword);
return t.contains(k);
}
Javaここでのポイントは、「どこまで正規化するかは要件次第」ということです。
全角・半角・濁点・カタカナ/ひらがななど、
全部を吸収しようとすると一気に難しくなります。
まずは「前後の空白を削る」「大文字小文字を揃える」くらいから始めて、
必要になったら正規化の範囲を広げていく、という段階的な考え方が現実的です。
実務で使える部分一致ユーティリティの形
「nullの扱い」と「正規化の方針」を決めておく
業務・実務で本当に使えるユーティリティにするには、
次のような点をきちんと決めておくことが大事です。
null が来たらどうするか(falseにするのか、例外にするのか)
大文字小文字を区別するか
前後の空白を無視するか
全角・半角をどこまで吸収するか
例えば、「ログメッセージにキーワードが含まれているか」を判定するユーティリティを、
大文字小文字と前後の空白を無視する形で書くと、こんな感じになります。
public final class LogMatchUtil {
private LogMatchUtil() {}
public static boolean containsKeyword(String logLine, String keyword) {
if (logLine == null || keyword == null) {
return false;
}
String lineNorm = logLine.trim().toLowerCase();
String keyNorm = keyword.trim().toLowerCase();
return lineNorm.contains(keyNorm);
}
}
JavaSystem.out.println(
LogMatchUtil.containsKeyword(" ERROR: something bad ", "error")
); // true
System.out.println(
LogMatchUtil.containsKeyword("INFO: ok", "error")
); // false
Javaこのように、「用途に合わせて“どう正規化してから部分一致するか”を決める」のが、
実務ユーティリティ設計のコツです。
まとめ:部分一致ユーティリティで身につけたい感覚
部分一致は、「この文字列の中に、別の文字列が含まれているか」を調べる、
文字列処理の超基本テクニックです。
Javaではまず
contains でシンプルな部分一致indexOf で位置も知るstartsWith / endsWith で前方・後方一致
を押さえ、そのうえで
大文字小文字を無視したいなら toLowerCase / toUpperCase で正規化
前後の空白や全角・半角をどう扱うかを決めてから比較
という「正規化+部分一致」のパターンを身につけておくと、
実務での検索・フィルタリング・ログ判定などが一気に書きやすくなります。
もしあなたのコードのどこかに、if (text.contains("ERROR")) { ... } のような生の条件が散らばっているなら、
それを一度 LogMatchUtil.containsKeyword のようなユーティリティにまとめてみてください。
その小さな整理が、「読みやすくて変更に強い文字列処理」を書けるエンジニアへの、確かな一歩になります。
