C# Tips | 文字列処理:正規表現一致判定

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

はじめに 「正規表現一致判定」は“文字列ルールをコードにする道具”

業務システムでは、「この文字列はメールアドレス形式か?」「このコードは英数字だけか?」「この入力は3桁の数字か?」といった“ルールチェック”が頻繁に出てきます。
そのときに強力な武器になるのが「正規表現」と、それを使った「一致判定(マッチ判定)」です。

C# では Regex.IsMatch を使うことで、「この文字列がパターンに合っているか?」を一発で判定できます。
ただし、正規表現は“強力すぎる”がゆえに、初心者がいきなり生で使うと「読めない・直せない・重い」の三重苦になりがちです。

ここでは、プログラミング初心者向けに、

  • Regex.IsMatch の基本
  • よくある業務パターン(数字チェック・英数字チェック・メール形式チェックなど)
  • null 安全なユーティリティ化
  • パフォーマンスを意識した「使い方のコツ」

を、例題付きでかみ砕いて説明していきます。


Regex.IsMatch の基本を押さえる

一番シンプルな使い方

まずは、Regex.IsMatch の基本形から見てみます。

using System.Text.RegularExpressions;

string input = "ABC123";

bool isMatch = Regex.IsMatch(input, "^[A-Z0-9]+$");

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

ここで使っている "^[A-Z0-9]+$" が「正規表現パターン」です。

  • ^ は「文字列の先頭」
  • [A-Z0-9] は「A〜Z または 0〜9 の 1 文字」
  • + は「1 文字以上の繰り返し」
  • $ は「文字列の末尾」

つまり、「先頭から末尾まで、全部が英大文字か数字で構成されているか?」をチェックしています。

Regex.IsMatch は、「マッチしたかどうか」を bool で返してくれるメソッドです。

部分一致ではなく“全体一致”を意識する

よくある勘違いが、「パターンを書いたのに、変な文字列にもマッチしてしまう」というものです。

例えば、こう書いたとします。

Regex.IsMatch("ABC123XYZ", "[0-9]+");
C#

これは true になります。
理由は、「どこか一部に数字の連続があれば OK」という“部分一致”だからです。

「文字列全体がそのパターンに合っているか?」を判定したいときは、
必ず ^(先頭)と $(末尾)を付けて「全体一致」にするのが重要です。

Regex.IsMatch("ABC123XYZ", "^[0-9]+$"); // false
Regex.IsMatch("12345",     "^[0-9]+$"); // true
C#

ここは、正規表現を使うときの超重要ポイントです。


よくある業務パターンを正規表現で書いてみる

数字だけかどうか(整数チェック)

「この文字列は数字だけで構成されているか?」は、業務でかなり頻出です。

bool IsDigits(string? value)
{
    if (string.IsNullOrEmpty(value))
    {
        return false;
    }

    return Regex.IsMatch(value, "^[0-9]+$");
}
C#

例です。

Console.WriteLine(IsDigits("123"));    // true
Console.WriteLine(IsDigits("00123"));  // true
Console.WriteLine(IsDigits("12A3"));   // false
Console.WriteLine(IsDigits(""));       // false
Console.WriteLine(IsDigits(null));     // false
C#

ここでは、

  • null や空文字は false
  • 1 桁以上の数字だけなら true

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

英数字だけかどうか(コード値チェック)

「顧客コード」「商品コード」などで、「英数字だけ」という制約もよくあります。

bool IsAlphaNumeric(string? value)
{
    if (string.IsNullOrEmpty(value))
    {
        return false;
    }

    return Regex.IsMatch(value, "^[A-Za-z0-9]+$");
}
C#

例です。

Console.WriteLine(IsAlphaNumeric("ABC123")); // true
Console.WriteLine(IsAlphaNumeric("abc123")); // true
Console.WriteLine(IsAlphaNumeric("A_BC123")); // false(アンダースコアが入っている)
Console.WriteLine(IsAlphaNumeric(""));        // false
C#

[A-Za-z0-9] は「英大文字・英小文字・数字」の 1 文字を意味します。

メールアドレス形式かどうか(簡易版)

メールアドレスの完全な正規表現はかなり複雑ですが、
業務では「ざっくり形式チェックできればいい」ということも多いです。

bool IsSimpleEmail(string? value)
{
    if (string.IsNullOrWhiteSpace(value))
    {
        return false;
    }

    string pattern = @"^[^@\s]+@[^@\s]+\.[^@\s]+$";

    return Regex.IsMatch(value, pattern);
}
C#

ここでのパターンの意味はざっくりこうです。

  • [^@\s]+ は「@ と空白以外の文字が 1 文字以上」
  • @ の前後にそれがあり、最後に . を挟んでまた同じような文字列がある

例です。

Console.WriteLine(IsSimpleEmail("user@example.com"));   // true
Console.WriteLine(IsSimpleEmail("user.name@domain.jp")); // true
Console.WriteLine(IsSimpleEmail("user@domain"));         // false(ドメインに . がない)
Console.WriteLine(IsSimpleEmail("user@@example.com"));   // false
Console.WriteLine(IsSimpleEmail(""));                    // false
C#

「完全に RFC 準拠」ではありませんが、
業務の入力チェックとしては十分なことが多いです。


null 安全な「正規表現一致ユーティリティ」を作る

毎回 null チェックを書くのはつらい

さきほどの例では、毎回こう書いていました。

if (string.IsNullOrEmpty(value))
{
    return false;
}
C#

これを毎回書くのは面倒なので、
「null 安全な IsMatch ユーティリティ」を 1 個用意しておくと便利です。

using System.Text.RegularExpressions;

public static class RegexUtil
{
    public static bool IsMatchSafe(string? value, string pattern, RegexOptions options = RegexOptions.None)
    {
        if (string.IsNullOrEmpty(value))
        {
            return false;
        }

        return Regex.IsMatch(value, pattern, options);
    }
}
C#

これを使うと、先ほどの IsDigits はこう書き換えられます。

bool IsDigits(string? value)
{
    return RegexUtil.IsMatchSafe(value, "^[0-9]+$");
}
C#

呼び出し側から見ると、

  • null のときは false
  • それ以外は普通に正規表現判定

という挙動が一目で分かります。


パフォーマンスを意識した「Regex の使い方」

毎回パターンをコンパイルし直すのはもったいない

Regex.IsMatch(string, string) のオーバーロードは、
内部的に「その場で Regex オブジェクトを作って、すぐ捨てる」という動きをします。

たまにしか呼ばれないなら問題ありませんが、
「同じパターンで何万回もチェックする」ような場面では、
毎回パターンを解釈し直すのはもったいないです。

Regex オブジェクトを使い回す

よく使うパターンは、Regex オブジェクトとして事前に用意しておき、
それを使い回すのが定番です。

using System.Text.RegularExpressions;

public static class RegexPatterns
{
    public static readonly Regex Digits =
        new Regex("^[0-9]+$", RegexOptions.Compiled);

    public static readonly Regex AlphaNumeric =
        new Regex("^[A-Za-z0-9]+$", RegexOptions.Compiled);

    public static readonly Regex SimpleEmail =
        new Regex(@"^[^@\s]+@[^@\s]+\.[^@\s]+$", RegexOptions.Compiled);
}
C#

使い方はこうです。

bool IsDigits(string? value)
{
    if (string.IsNullOrEmpty(value))
    {
        return false;
    }

    return RegexPatterns.Digits.IsMatch(value);
}
C#

RegexOptions.Compiled を付けると、「パターンを事前にコンパイルしておいて、実行時のマッチングを速くする」ことができます。
(ただし、コンパイルのコストもあるので、「よく使うパターン」にだけ付けるのが現実的です。)


実務での設計ポイント 「正規表現そのものを散らさない」

パターン文字列をあちこちにベタ書きしない

悪い例を一つ挙げます。

if (!Regex.IsMatch(code, "^[A-Za-z0-9]+$"))
{
    // エラー
}

if (!Regex.IsMatch(userId, "^[A-Za-z0-9]+$"))
{
    // 別の場所でも同じパターン
}
C#

同じ "^[A-Za-z0-9]+$" が、コードのあちこちにベタ書きされている状態です。
こうなると、

  • パターンを修正したいときに、全部探して直さないといけない
  • どれが同じルールで、どれが違うルールなのか分かりにくい
  • 正規表現が読めない人には、何をチェックしているのか伝わらない

という問題が出てきます。

「意味のある名前を付けたユーティリティ」に閉じ込める

さきほどのように、

  • RegexPatterns にパターンをまとめる
  • RegexUtil.IsMatchSafe で null 安全にする
  • さらに IsDigitsIsAlphaNumeric のような“意味のある名前”のメソッドにする

という段階までやっておくと、呼び出し側はこう書けます。

if (!IsAlphaNumeric(code))
{
    // 英数字以外が含まれているエラー
}
C#

「何をチェックしているのか」が、正規表現を読めなくても分かります。
正規表現そのものは、ユーティリティの中に閉じ込めておくイメージです。


まとめ 「正規表現一致ユーティリティ」は“文字列ルールを一箇所に集約する仕組み”

正規表現一致判定は、「文字列がルールに合っているか?」を機械的にチェックする強力な道具です。
ただし、そのまま乱用すると「読めない・直せない・重い」コードになりがちです。

押さえておきたいポイントをまとめると、

  • Regex.IsMatch は「パターンにマッチしたか?」を bool で返す
  • 「全体一致」をしたいときは、必ず ^$ を付ける
  • null 安全な IsMatchSafe のようなユーティリティを用意しておくと、呼び出し側が楽になる
  • よく使うパターンは Regex オブジェクトとして定義し、RegexOptions.Compiled で使い回す
  • 正規表現パターンをあちこちにベタ書きせず、「意味のある名前のメソッド」に閉じ込める

ここまでできれば、「とりあえず正規表現を書いてみた」段階から一歩進んで、
“文字列ルールを一箇所に集約して、安全かつ効率よくチェックする”ための
C# ユーティリティを設計・実装できるようになっていきます。

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