C# Tips | 文字列処理:部分一致検索

C# C#
スポンサーリンク

はじめに 「部分一致検索」は“文字列の中から、手がかりを探す”作業

業務システムでは、こういうことをよくやります。

  • 商品名に「りんご」が含まれているデータだけを抽出したい
  • ログの1行の中に「ERROR」という文字が含まれているか調べたい
  • 入力されたキーワードが、候補リストのどれかに含まれているか調べたい

これが、文字列の「部分一致検索」です。

C#では string.Contains を使うのが基本ですが、
そのままだと「大文字・小文字を区別する」「カルチャの影響を受ける」など、
業務で使うには少し物足りないところがあります。

ここでは、初心者向けに、

  • 部分一致検索の基本
  • 大文字無視での部分一致
  • 実務で使いやすいユーティリティ化

を、例題を交えながら丁寧に解説していきます。


基本:string.Contains で「含まれているか」を調べる

まずは素の Contains の挙動を知る

一番シンプルな部分一致検索は、string.Contains です。

string text = "今日はとてもいい天気です。";

Console.WriteLine(text.Contains("天気")); // True
Console.WriteLine(text.Contains("雨"));   // False
C#

text.Contains("天気") は、
text の中に "天気" という文字列が含まれているか?」を調べています。

True → 含まれている
False → 含まれていない

という、とても分かりやすいメソッドです。

ただし、デフォルトでは「大文字・小文字を区別する」

英字を含む文字列で試してみます。

string text = "Error: File Not Found";

Console.WriteLine(text.Contains("Error")); // True
Console.WriteLine(text.Contains("error")); // False
C#

"Error" は含まれていますが、
"error"(全部小文字)は「含まれていない」と判定されます。

つまり、デフォルトの Contains は大文字・小文字を区別する、ということです。

「ERROR でも error でも ErrOr でもいいから、とにかく“エラー”を検出したい」
という業務的な要件には、そのままだと足りません。


正しい方向性:StringComparison を指定して部分一致する

Contains にも「比較ルールを指定できる版」がある

C# には、比較ルールを指定するための StringComparison という列挙型があります。
EqualsStartsWith だけでなく、Contains にもこれを渡せます。

string text = "Error: File Not Found";

bool hasError = text.Contains("error", StringComparison.OrdinalIgnoreCase);

Console.WriteLine(hasError); // True
C#

StringComparison.OrdinalIgnoreCase を指定することで、

  • 大文字・小文字を無視する
  • 文化(カルチャ)に依存しない、シンプルな比較

という動きになります。

業務システムで「コード」「フラグ」「キーワード」などを検索するときは、
まずこの OrdinalIgnoreCase を選んでおけば安全です。


実務で使えるユーティリティメソッドの形

「大文字無視の部分一致」を一言で書けるようにする

毎回 StringComparison.OrdinalIgnoreCase と書くのは長いので、
ユーティリティメソッドに閉じ込めてしまうのがおすすめです。

public static class StringSearchUtil
{
    public static bool ContainsIgnoreCase(string? text, string? value)
    {
        if (string.IsNullOrEmpty(text) || string.IsNullOrEmpty(value))
        {
            return false;
        }

        return text.Contains(value, StringComparison.OrdinalIgnoreCase);
    }
}
C#

使い方はこうなります。

Console.WriteLine(StringSearchUtil.ContainsIgnoreCase("Error: File Not Found", "error")); // True
Console.WriteLine(StringSearchUtil.ContainsIgnoreCase("STATUS=OK", "ok"));                // True
Console.WriteLine(StringSearchUtil.ContainsIgnoreCase("STATUS=NG", "ok"));                // False
Console.WriteLine(StringSearchUtil.ContainsIgnoreCase(null, "ok"));                       // False
Console.WriteLine(StringSearchUtil.ContainsIgnoreCase("text", null));                     // False
C#

ここでのポイントは、

  • null や空文字が来たら、素直に false を返す
  • 呼び出し側が毎回 null チェックを書かなくていい

という設計にしていることです。


重要ポイント:StringComparison の選び方をざっくり理解する

Ordinal と CurrentCulture の違い

StringComparison にはいくつか種類がありますが、
実務でよく使うのは主に次の2系統です。

Ordinal / OrdinalIgnoreCase

  • 文字コード(ほぼバイト列)に近い比較
  • 文化(カルチャ)に依存しない
  • コード値、ID、フラグ、ログのキーワードなどに向いている
text.Contains("error", StringComparison.OrdinalIgnoreCase);
C#

CurrentCulture / CurrentCultureIgnoreCase

  • 実行環境の文化(日本語環境、英語環境など)に応じた比較
  • 人間の言語感覚に近い比較
  • 画面表示用の検索やソートなどで使うことがある

初心者のうちは、
「システム内部の検索 → OrdinalIgnoreCase」
と覚えておけば十分です。


部分一致検索の実務的な使いどころ

ログから「エラー行」だけを拾う

例えば、ログの1行を受け取って、
「エラー行かどうか」を判定するユーティリティを考えてみます。

public static class LogUtil
{
    public static bool IsErrorLine(string? line)
    {
        return StringSearchUtil.ContainsIgnoreCase(line, "error")
            || StringSearchUtil.ContainsIgnoreCase(line, "exception")
            || StringSearchUtil.ContainsIgnoreCase(line, "fatal");
    }
}
C#

使い方はこうです。

string line1 = "[INFO] Application started.";
string line2 = "[ERROR] Database connection failed.";
string line3 = "[Fatal] Unexpected exception occurred.";

Console.WriteLine(LogUtil.IsErrorLine(line1)); // False
Console.WriteLine(LogUtil.IsErrorLine(line2)); // True
Console.WriteLine(LogUtil.IsErrorLine(line3)); // True
C#

ERROR / Error / error など、
大文字・小文字の揺れを気にせずに判定できます。

商品名や説明文からキーワード検索

public static bool ContainsKeyword(string? text, string? keyword)
{
    return StringSearchUtil.ContainsIgnoreCase(text, keyword);
}
C#
string name = "青森県産りんごジュース";

Console.WriteLine(ContainsKeyword(name, "りんご")); // True
Console.WriteLine(ContainsKeyword(name, "みかん")); // False
C#

日本語の場合は大文字・小文字の問題は少ないですが、
英数字が混ざるケース(型番、コードなど)では IgnoreCase が効いてきます。


もう一歩:インデックスが欲しい場合は IndexOf を使う

「どこに含まれているか」まで知りたいとき

Contains は「含まれているかどうか」だけですが、
「何文字目に出てきたか」を知りたいときは IndexOf を使います。

public static int IndexOfIgnoreCase(string? text, string? value)
{
    if (string.IsNullOrEmpty(text) || string.IsNullOrEmpty(value))
    {
        return -1;
    }

    return text.IndexOf(value, StringComparison.OrdinalIgnoreCase);
}
C#

使い方はこうです。

string text = "Error: File Not Found";

int index = IndexOfIgnoreCase(text, "file");

Console.WriteLine(index); // 7(0始まり)
C#

-1 → 見つからない
0以上 → 見つかった位置

というルールです。

「見つかったら、その前後の文字列を切り出したい」
「最初に出てきた位置だけ知りたい」
といったときに便利です。


業務ユーティリティとしてどうまとめるか

「検索系」をひとまとめにしておく

実務でよく使うのは、だいたい次の3つです。

public static class StringSearchUtil
{
    public static bool ContainsIgnoreCase(string? text, string? value)
    {
        if (string.IsNullOrEmpty(text) || string.IsNullOrEmpty(value))
        {
            return false;
        }

        return text.Contains(value, StringComparison.OrdinalIgnoreCase);
    }

    public static int IndexOfIgnoreCase(string? text, string? value)
    {
        if (string.IsNullOrEmpty(text) || string.IsNullOrEmpty(value))
        {
            return -1;
        }

        return text.IndexOf(value, StringComparison.OrdinalIgnoreCase);
    }

    public static bool StartsWithIgnoreCase(string? text, string? prefix)
    {
        if (text is null || prefix is null)
        {
            return false;
        }

        return text.StartsWith(prefix, StringComparison.OrdinalIgnoreCase);
    }
}
C#

これを用意しておくと、呼び出し側は

if (StringSearchUtil.ContainsIgnoreCase(message, "timeout"))
{
    // タイムアウト系エラーとして扱う
}

if (StringSearchUtil.StartsWithIgnoreCase(code, "ERR"))
{
    // エラーコードとして扱う
}
C#

のように、「何をしたいか」が一目で分かるコードを書けます。

null の扱いを“ユーティリティ側で固定する”

今回の実装では、

  • textvalue が null / 空 → 「見つからない」と判定(false / -1

というルールにしています。

これにより、呼び出し側は

  • 毎回 null チェックを書かなくていい
  • 「とりあえずそのまま渡せばいい」という気持ちで使える

ようになります。

プロジェクトによっては、

  • null が来たら例外
  • 空文字は特別扱い

などのポリシーもあり得ますが、
大事なのは「ユーティリティ側でルールを決めておく」ことです。


まとめ 「部分一致検索ユーティリティ」は“文字列の中から意味をすくい上げる道具”

部分一致検索は、ログ解析、検索機能、バリデーション、コード判定など、
業務のあちこちで使われる“地味だけど超重要なテクニック”です。

押さえておきたいポイントは、

  • string.Contains はデフォルトだと大文字・小文字を区別すること。
  • Contains(value, StringComparison.OrdinalIgnoreCase) のように、比較ルールを明示するのが実務的で安全なこと。
  • ContainsIgnoreCaseIndexOfIgnoreCase をユーティリティ化しておくと、呼び出し側のコードが読みやすく・バグりにくくなること。
  • null や空文字の扱いをユーティリティ側で決めておくと、業務コードがすっきりすること。

ここまで理解できれば、「なんとなく Contains している」段階から一歩進んで、
“意図のはっきりした、業務で使える部分一致検索ユーティリティ”を、
自分のC#コードの中に自然に組み込めるようになっていきます。

タイトルとURLをコピーしました