はじめに 「正規表現一致判定」は“文字列ルールをコードにする道具”
業務システムでは、「この文字列はメールアドレス形式か?」「このコードは英数字だけか?」「この入力は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 安全にする- さらに
IsDigitsやIsAlphaNumericのような“意味のある名前”のメソッドにする
という段階までやっておくと、呼び出し側はこう書けます。
if (!IsAlphaNumeric(code))
{
// 英数字以外が含まれているエラー
}
C#「何をチェックしているのか」が、正規表現を読めなくても分かります。
正規表現そのものは、ユーティリティの中に閉じ込めておくイメージです。
まとめ 「正規表現一致ユーティリティ」は“文字列ルールを一箇所に集約する仕組み”
正規表現一致判定は、「文字列がルールに合っているか?」を機械的にチェックする強力な道具です。
ただし、そのまま乱用すると「読めない・直せない・重い」コードになりがちです。
押さえておきたいポイントをまとめると、
Regex.IsMatchは「パターンにマッチしたか?」を bool で返す- 「全体一致」をしたいときは、必ず
^と$を付ける - null 安全な
IsMatchSafeのようなユーティリティを用意しておくと、呼び出し側が楽になる - よく使うパターンは
Regexオブジェクトとして定義し、RegexOptions.Compiledで使い回す - 正規表現パターンをあちこちにベタ書きせず、「意味のある名前のメソッド」に閉じ込める
ここまでできれば、「とりあえず正規表現を書いてみた」段階から一歩進んで、
“文字列ルールを一箇所に集約して、安全かつ効率よくチェックする”ための
C# ユーティリティを設計・実装できるようになっていきます。
