csharp regex入門:C#で正規表現を使う方法をサンプル付きで徹底解説

はじめに

C#で文字列処理をしていると、「メールアドレスの形式をチェックしたい」「ログから日時だけを取り出したい」「HTMLタグを削除したい」「数字だけを抽出したい」といった場面がよくあります。こうした処理で便利なのが、正規表現を扱うためのC#の機能であるRegexです。

「csharp regex」と検索している人の多くは、C#で正規表現を使う具体的な書き方や、Regex.IsMatchRegex.MatchRegex.Replaceなどの使い方を知りたいはずです。正規表現は一見難しく見えますが、基本的な記号とC#での書き方を押さえれば、入力チェックや文字列抽出を効率よく実装できます。

この記事では、C#で正規表現を使うための基礎から、実務で使えるサンプル、グループ化、RegexOptions、パフォーマンス対策、よくあるエラーまで、初心者にもわかりやすく解説します。

1. csharp regexとは?C#で正規表現を使う前に知っておきたい基礎

「csharp regex」とは、C#で正規表現を使う方法を指して検索されることが多いキーワードです。C#では、正規表現を扱うためにSystem.Text.RegularExpressions.Regexクラスを使用します。

正規表現とは、文字列のパターンを表現するための記法です。たとえば、数字だけに一致させる、メールアドレスらしい文字列を探す、空白をまとめて置換する、といった処理を短いパターンで書けます。

C#
using System.Text.RegularExpressions;

string input = "abc123";
bool result = Regex.IsMatch(input, @"\d+");

Console.WriteLine(result); // True

上の例では、@"\d+"という正規表現で「1文字以上の数字」が含まれているかを判定しています。

1-1. 正規表現でできること:検索・判定・抽出・置換・分割

C#のRegexを使うと、主に次のような文字列処理ができます。

文字列が特定の形式に一致するか判定できます。たとえば、ユーザーが入力した値が郵便番号、電話番号、メールアドレスの形式になっているかを確認できます。

C#
bool isZipCode = Regex.IsMatch("123-4567", @"^\d{3}-\d{4}$");

文字列の中から特定のパターンに一致する部分を抽出できます。

C#
Match match = Regex.Match("注文番号: 12345", @"\d+");
Console.WriteLine(match.Value); // 12345

一致した文字列を別の文字列に置換できます。

C#
string result = Regex.Replace("電話: 090-1234-5678", @"\d", "*");
Console.WriteLine(result); // 電話: ***-****-****

正規表現に一致する箇所で文字列を分割できます。

C#
string[] items = Regex.Split("apple, orange; banana", @"[,;]\s*");

このように、Regexは検索、判定、抽出、置換、分割をまとめて扱える強力な文字列処理機能です。

1-2. C#ではSystem.Text.RegularExpressions.Regexクラスを使う

C#で正規表現を使うには、基本的にRegexクラスを使います。RegexクラスはSystem.Text.RegularExpressions名前空間に含まれています。

C#
using System.Text.RegularExpressions;

このusingを追加すると、Regex.IsMatchRegex.Matchなどを短い名前で使えるようになります。

C#
string input = "user@example.com";
string pattern = @"^[^@\s]+@[^@\s]+\.[^@\s]+$";

bool isValid = Regex.IsMatch(input, pattern);
Console.WriteLine(isValid);

Regexクラスには、静的メソッドとして使う方法と、インスタンスを作成して使う方法があります。簡単な処理では静的メソッドで十分ですが、同じ正規表現を何度も使う場合はインスタンス化して再利用するのがおすすめです。

1-3. 「csharp regex」と「C# 正規表現」の違いと検索される理由

「csharp regex」と「C# 正規表現」は、ほぼ同じ意味で使われます。

「regex」は「regular expression」の略で、日本語では「正規表現」と訳されます。そのため、「csharp regex」は「C#で正規表現を使う方法」という意味になります。

日本語では「C# 正規表現」と検索されることが多い一方で、英語のサンプルコードや公式ドキュメントではRegexというクラス名が使われるため、「csharp regex」というキーワードでも多く検索されます。

特にC#ではクラス名がRegexなので、次のような疑問を持つ人が検索します。

C#でRegexを使うにはどう書くのか、Regex.MatchRegex.Matchesの違いは何か、@"\d+"のような書き方は何を意味するのか、RegexOptionsはいつ使うのか、といった内容です。

この記事では、日本語の「C# 正規表現」と英語寄りの「csharp regex」の両方を意識しながら解説します。

1-4. Regexを使うべきケースとStringメソッドで十分なケース

Regexは便利ですが、すべての文字列処理に使うべきではありません。単純な処理であれば、Stringクラスのメソッドを使ったほうが読みやすく、速く、保守しやすいことがあります。

たとえば、特定の文字列を含むか確認するだけならContainsで十分です。

C#
string text = "Hello C# Regex";

bool contains = text.Contains("Regex");

先頭や末尾を確認するだけなら、StartsWithEndsWithが適しています。

C#
bool starts = text.StartsWith("Hello");
bool ends = text.EndsWith("Regex");

単純な置換ならReplaceで十分です。

C#
string result = text.Replace("Regex", "正規表現");

一方で、次のようなケースではRegexが向いています。

入力値が複雑な形式に一致するかチェックしたい場合、文字列の中から特定のパターンを抽出したい場合、複数種類の区切り文字で分割したい場合、連続する空白を1つにまとめたい場合、ログやCSV風の文字列から値を取り出したい場合です。

つまり、単純な文字列一致ならStringメソッド、パターンに基づく処理ならRegexと考えるとよいでしょう。

2. C#でRegexを使うための準備

C#でRegexを使うために必要な準備は多くありません。基本的には名前空間を追加し、パターン文字列を用意して、Regexクラスのメソッドを呼び出すだけです。

ただし、初心者がつまずきやすいポイントとして、C#の文字列リテラルと正規表現のエスケープがあります。特にバックスラッシュの扱いを理解しておくと、csharp regexのコードがかなり読みやすくなります。

2-1. using System.Text.RegularExpressionsを追加する

Regexを使うには、ファイルの先頭に次のusingを追加します。

C#
using System.Text.RegularExpressions;

これにより、次のようにRegexクラスを直接使えます。

C#
string input = "abc123";
bool hasNumber = Regex.IsMatch(input, @"\d");

Console.WriteLine(hasNumber); // True

もしusingを書かない場合は、完全修飾名で書くこともできます。

C#
bool hasNumber = System.Text.RegularExpressions.Regex.IsMatch("abc123", @"\d");

ただし、通常はusing System.Text.RegularExpressions;を追加するほうが読みやすいです。

2-2. Regexクラスの基本的な書き方

C# Regexの基本形は、入力文字列と正規表現パターンを指定してメソッドを呼び出す形です。

C#
Regex.IsMatch(入力文字列, 正規表現パターン);
Regex.Match(入力文字列, 正規表現パターン);
Regex.Matches(入力文字列, 正規表現パターン);
Regex.Replace(入力文字列, 正規表現パターン, 置換後文字列);
Regex.Split(入力文字列, 正規表現パターン);

具体例を見てみましょう。

C#
string input = "商品コード: A-12345";
string pattern = @"[A-Z]-\d+";

Match match = Regex.Match(input, pattern);

if (match.Success)
{
Console.WriteLine(match.Value); // A-12345
}

この例では、英大文字1文字、ハイフン、1文字以上の数字というパターンに一致する部分を取得しています。

2-3. 静的メソッドとRegexインスタンスの使い分け

Regexには、静的メソッドとして使う方法と、インスタンスを作成して使う方法があります。

静的メソッドは、手軽に1回だけ使いたいときに便利です。

C#
bool result = Regex.IsMatch("abc123", @"\d+");

一方、同じ正規表現を何度も使う場合は、Regexインスタンスを作成して再利用するとコードが整理されます。

C#
var regex = new Regex(@"^\d{3}-\d{4}$");

Console.WriteLine(regex.IsMatch("123-4567")); // True
Console.WriteLine(regex.IsMatch("12-34567")); // False

たとえば、ユーザー入力を何度も検証する場合や、ループの中で同じパターンを使う場合は、インスタンス化しておくとよいでしょう。

C#
var zipRegex = new Regex(@"^\d{3}-\d{4}$");

foreach (var value in values)
{
if (zipRegex.IsMatch(value))
{
Console.WriteLine($"{value} は郵便番号形式です");
}
}

2-4. C#の文字列リテラルと正規表現:@""を使う理由

C#で正規表現を書くときは、@""を使った逐語的文字列リテラルがよく使われます。

C#
string pattern = @"\d+";

@""を使うと、バックスラッシュを通常の文字として扱いやすくなります。正規表現では\d\sのようにバックスラッシュを多用するため、@""を使うと読みやすくなります。

通常の文字列リテラルで書く場合は、バックスラッシュ自体をエスケープする必要があります。

C#
string pattern1 = @"\d+";
string pattern2 = "\\d+";

この2つは、正規表現としては同じ意味です。しかし、"\\d+"よりも@"\d+"のほうが読みやすいため、C# Regexでは@""がよく使われます。

ただし、@""内でダブルクォートを表したい場合は、""と2つ重ねます。

C#
string pattern = @"name=""([^""]+)""";

2-5. バックスラッシュのエスケープで初心者がつまずくポイント

C# Regexで初心者が特につまずきやすいのが、バックスラッシュのエスケープです。

正規表現では、数字を表す\d、空白を表す\s、単語文字を表す\wなどを使います。しかし、C#の通常文字列では\にも特別な意味があるため、正しくエスケープしないと意図しない文字列になります。

たとえば、次のコードはエラーになります。

C#
string pattern = "\d+";

C#の通常文字列では、\dが有効なエスケープシーケンスではないためです。

正しくは、次のどちらかで書きます。

C#
string pattern1 = @"\d+";
string pattern2 = "\\d+";

基本的には、正規表現パターンを書くときは@""を使う、と覚えておくと失敗が減ります。

ファイルパスのようにバックスラッシュを含む文字列を扱う場合も注意が必要です。

C#
string input = @"C:\Users\Taro\Documents";
bool result = Regex.IsMatch(input, @"C:\\Users\\");

入力文字列と正規表現パターンの両方でバックスラッシュが出てくると混乱しやすいため、まずは「C#の文字列としてどう解釈されるか」と「正規表現としてどう解釈されるか」を分けて考えることが大切です。

3. C# Regexの基本メソッドをサンプル付きで解説

C# Regexでよく使う基本メソッドは、IsMatchMatchMatchesReplaceSplitです。これらを覚えるだけでも、多くの文字列処理を実装できます。

それぞれの違いを簡単に整理すると、IsMatchは一致するかどうかの判定、Matchは最初の一致を取得、Matchesはすべての一致を取得、Replaceは置換、Splitは分割に使います。

3-1. IsMatch:文字列がパターンに一致するか判定する

IsMatchは、入力文字列が正規表現パターンに一致するかどうかをboolで返します。

C#
using System.Text.RegularExpressions;

string input = "12345";
bool result = Regex.IsMatch(input, @"^\d+$");

Console.WriteLine(result); // True

この例では、^\d+$というパターンを使っています。

^は文字列の先頭、\d+は1文字以上の数字、$は文字列の末尾を表します。つまり、文字列全体が数字だけで構成されているかを判定しています。

次のように、入力チェックでよく使われます。

C#
string password = "abc123";

if (Regex.IsMatch(password, @"^[a-zA-Z0-9]+$"))
{
Console.WriteLine("英数字のみです");
}
else
{
Console.WriteLine("使用できない文字が含まれています");
}

3-2. Match:最初に一致した文字列を取得する

Matchは、最初に一致した部分を取得します。

C#
string input = "商品ID: 98765, 在庫: 20";
Match match = Regex.Match(input, @"\d+");

if (match.Success)
{
Console.WriteLine(match.Value); // 98765
}

Regex.Matchの戻り値はMatchオブジェクトです。match.Successで一致したかどうかを確認し、match.Valueで一致した文字列を取得します。

最初の一致だけが必要な場合はMatchを使います。たとえば、文章内に最初に出てくる数値だけを取り出す場合に便利です。

C#
string text = "価格は税込1280円です";
Match price = Regex.Match(text, @"\d+");

if (price.Success)
{
Console.WriteLine($"価格: {price.Value}円");
}

3-3. Matches:一致した文字列をすべて取得する

Matchesは、文字列内にあるすべての一致を取得します。

C#
string input = "A001 B202 C333";
MatchCollection matches = Regex.Matches(input, @"[A-Z]\d{3}");

foreach (Match match in matches)
{
Console.WriteLine(match.Value);
}

実行結果は次のようになります。

A001
B202
C333

Matchesは、ログからすべてのエラーコードを取り出す場合や、文章内のURLをすべて抽出する場合などに使えます。

C#
string text = "連絡先: 090-1111-2222 / 03-1234-5678";
MatchCollection phones = Regex.Matches(text, @"\d{2,4}-\d{3,4}-\d{4}");

foreach (Match phone in phones)
{
Console.WriteLine(phone.Value);
}

3-4. Replace:一致した文字列を置換・削除する

Replaceは、正規表現に一致した部分を別の文字列に置換します。

C#
string input = "abc123def456";
string result = Regex.Replace(input, @"\d+", "#");

Console.WriteLine(result); // abc#def#

一致部分を空文字に置換すれば、削除として使えます。

C#
string input = "電話番号: 090-1234-5678";
string result = Regex.Replace(input, @"\D", "");

Console.WriteLine(result); // 09012345678

この例では、\Dが「数字以外」を表すため、数字以外の文字をすべて削除しています。

連続する空白を1つにまとめる処理もよく使われます。

C#
string input = "C#   Regex    入門";
string result = Regex.Replace(input, @"\s+", " ");

Console.WriteLine(result); // C# Regex 入門

3-5. Split:正規表現に一致する箇所で文字列を分割する

Splitは、正規表現に一致する箇所で文字列を分割します。

C#
string input = "apple,orange;banana grape";
string[] items = Regex.Split(input, @"[,;\s]+");

foreach (string item in items)
{
Console.WriteLine(item);
}

実行結果は次のようになります。

apple
orange
banana
grape

通常のstring.Splitでも分割はできますが、複数の区切り文字や連続する空白をまとめて扱いたい場合はRegex.Splitが便利です。

C#
string input = "red,,blue; green   yellow";
string[] colors = Regex.Split(input, @"[,;\s]+");

foreach (string color in colors)
{
Console.WriteLine(color);
}

3-6. Match.Success・Value・Index・Lengthの使い方

Matchオブジェクトには、一致結果を扱うための便利なプロパティがあります。

Successは一致したかどうか、Valueは一致した文字列、Indexは一致した位置、Lengthは一致した文字数を表します。

C#
string input = "Order No: ABC-12345";
Match match = Regex.Match(input, @"[A-Z]{3}-\d+");

if (match.Success)
{
Console.WriteLine(match.Value); // ABC-12345
Console.WriteLine(match.Index); // 一致開始位置
Console.WriteLine(match.Length); // 一致文字数
}

Indexは0から始まる位置です。たとえば、文字列のどこに一致したのかを調べたい場合に使えます。

C#
string input = "abc 123 def";
Match match = Regex.Match(input, @"\d+");

if (match.Success)
{
Console.WriteLine($"値: {match.Value}");
Console.WriteLine($"開始位置: {match.Index}");
Console.WriteLine($"長さ: {match.Length}");
}

Matchを使うときは、必ずSuccessを確認してからValueなどを参照する習慣をつけると安全です。

4. よく使う正規表現パターン一覧

C# Regexを使いこなすには、よく使う正規表現の記号を覚えることが大切です。最初からすべてを暗記する必要はありませんが、\d\w\s^$+*[]あたりは頻繁に使います。

ここでは、実務でもよく登場する基本パターンを紹介します。

4-1. 数字に一致する:\d

\dは数字1文字に一致します。

C#
bool result = Regex.IsMatch("abc123", @"\d");
Console.WriteLine(result); // True

1文字以上の数字に一致させたい場合は、+を付けます。

C#
Match match = Regex.Match("価格は1200円です", @"\d+");
Console.WriteLine(match.Value); // 1200

数字だけの文字列か判定したい場合は、先頭と末尾を指定します。

C#
bool result = Regex.IsMatch("12345", @"^\d+$");

^\d+$は、文字列全体が1文字以上の数字で構成されていることを表します。

4-2. 英字・単語文字に一致する:\w

\wは単語文字に一致します。一般的には英数字とアンダースコアに一致するものとして使われます。

C#
bool result = Regex.IsMatch("abc_123", @"^\w+$");
Console.WriteLine(result); // True

ただし、.NETの正規表現ではUnicode文字も考慮されるため、環境やオプションによって日本語などが関係する場面では注意が必要です。

英数字だけを明確に許可したい場合は、\wではなく文字クラスを使うほうが意図が伝わりやすいです。

C#
bool result = Regex.IsMatch("abc123", @"^[a-zA-Z0-9]+$");

アンダースコアも許可したい場合は、次のように書けます。

C#
bool result = Regex.IsMatch("abc_123", @"^[a-zA-Z0-9_]+$");

4-3. 空白に一致する:\s

\sは空白文字に一致します。半角スペースだけでなく、タブや改行なども対象になります。

C#
string input = "C#   Regex\t入門";
string result = Regex.Replace(input, @"\s+", " ");

Console.WriteLine(result); // C# Regex 入門

\s+は、1文字以上の空白に一致します。文章の余分な空白を整理する処理でよく使います。

半角スペースだけに一致させたい場合は、\sではなくスペースをそのまま書くか、[ ]を使います。

C#
string result = Regex.Replace(input, @"[ ]+", " ");

4-4. 任意の1文字に一致する:.

.は任意の1文字に一致します。

C#
bool result = Regex.IsMatch("abc", @"a.c");
Console.WriteLine(result); // True

この例では、a、任意の1文字、cという並びに一致します。そのため、abca1ca-cなどに一致します。

ただし、通常の設定では.は改行には一致しません。改行も含めて一致させたい場合は、RegexOptions.Singlelineを使います。

C#
string input = "start\nend";
bool result = Regex.IsMatch(input, @"start.*end", RegexOptions.Singleline);

.自体に一致させたい場合は、エスケープして\.と書きます。

C#
bool result = Regex.IsMatch("example.com", @"\.");

4-5. 文字数を指定する:*・+・?・{n,m}

正規表現では、直前の文字やパターンの繰り返し回数を指定できます。

*は0回以上、+は1回以上、?は0回または1回、{n}はちょうどn回、{n,m}はn回以上m回以下を表します。

C#
Regex.IsMatch("aaa", @"a*");     // aが0回以上
Regex.IsMatch("aaa", @"a+"); // aが1回以上
Regex.IsMatch("color", @"colou?r"); // uが0回または1回
Regex.IsMatch("123", @"^\d{3}$"); // 数字3桁
Regex.IsMatch("12345", @"^\d{3,5}$"); // 数字3〜5桁

郵便番号のチェックでは、\d{3}-\d{4}のように桁数を指定します。

C#
bool result = Regex.IsMatch("123-4567", @"^\d{3}-\d{4}$");

電話番号のように桁数に幅がある場合は、{2,4}のように書けます。

C#
bool result = Regex.IsMatch("03-1234-5678", @"^\d{2,4}-\d{2,4}-\d{4}$");

4-6. 先頭と末尾を指定する:^・$

^は文字列の先頭、$は文字列の末尾を表します。

C#
bool result = Regex.IsMatch("12345", @"^\d+$");

この例では、文字列全体が数字だけであるかを判定しています。

^$を使わない場合、文字列の一部に一致すればtrueになります。

C#
Console.WriteLine(Regex.IsMatch("abc123def", @"\d+"));   // True
Console.WriteLine(Regex.IsMatch("abc123def", @"^\d+$")); // False

入力チェックでは、部分一致ではなく全体一致を確認したいことが多いため、^$を忘れないようにしましょう。

複数行の文字列で各行の先頭や末尾を扱いたい場合は、RegexOptions.Multilineを使います。

4-7. いずれかに一致する:[]・|

[]は、指定した文字のいずれか1文字に一致します。

C#
bool result = Regex.IsMatch("cat", @"c[au]t");

このパターンは、catまたはcutに一致します。

範囲を指定することもできます。

C#
Regex.IsMatch("A", @"[A-Z]");
Regex.IsMatch("7", @"[0-9]");
Regex.IsMatch("m", @"[a-z]");

|は、複数のパターンのいずれかに一致させるときに使います。

C#
bool result = Regex.IsMatch("apple", @"apple|orange|banana");

グループ化と組み合わせることもよくあります。

C#
bool result = Regex.IsMatch("color", @"colou?r|color");

より簡潔に書くなら、次のようにできます。

C#
bool result = Regex.IsMatch("color", @"colou?r");

4-8. 否定条件を指定する:[^]

[^...]は、指定した文字以外に一致します。

C#
string input = "abc123";
string result = Regex.Replace(input, @"[^0-9]", "");

Console.WriteLine(result); // 123

この例では、数字以外を削除して数字だけを取り出しています。

英数字以外を削除する場合は、次のように書けます。

C#
string input = "abc-123_@";
string result = Regex.Replace(input, @"[^a-zA-Z0-9]", "");

Console.WriteLine(result); // abc123

注意点として、^は使う場所によって意味が変わります。文字クラスの外では先頭を表しますが、[]の中の先頭に書くと否定を表します。

C#
@"^\d+$"     // 文字列全体が数字
@"[^0-9]" // 数字以外の1文字

4-9. 日本語・ひらがな・カタカナ・漢字に一致させる方法

日本語を正規表現で扱う場合は、Unicode範囲を使う方法があります。

ひらがなに一致させる例です。

C#
bool result = Regex.IsMatch("こんにちは", @"^[\u3040-\u309F]+$");

カタカナに一致させる例です。

C#
bool result = Regex.IsMatch("カタカナ", @"^[\u30A0-\u30FF]+$");

漢字に一致させる例です。

C#
bool result = Regex.IsMatch("日本語", @"^[\u4E00-\u9FFF]+$");

ひらがな、カタカナ、漢字をまとめて許可したい場合は、次のように書けます。

C#
bool result = Regex.IsMatch("山田タロウ", @"^[\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FFF]+$");

全角スペースや長音記号も許可したい場合は、必要に応じて文字クラスに追加します。

C#
bool result = Regex.IsMatch("山田 太郎", @"^[\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FFFー \s]+$");

日本語の入力チェックでは、許可したい文字を明確にすることが重要です。ひらがなだけなのか、カタカナも許可するのか、漢字も必要なのか、全角スペースや記号をどう扱うのかを先に決めてからパターンを作りましょう。

5. 実務で使えるC# Regexサンプル集

ここからは、実務でよく使うC# Regexのサンプルを紹介します。入力チェック、抽出、置換など、アプリケーション開発でよく登場する処理を中心に解説します。

ただし、正規表現による入力チェックは「形式の簡易チェック」として使うのが基本です。メールアドレスやURLなどは仕様が複雑なため、厳密に判定しようとすると正規表現が非常に複雑になります。実務では、必要な要件に合わせて適度なパターンを使うことが大切です。

5-1. メールアドレス形式をチェックする

メールアドレス形式を簡易チェックする例です。

C#
string email = "user@example.com";
string pattern = @"^[^@\s]+@[^@\s]+\.[^@\s]+$";

bool isValid = Regex.IsMatch(email, pattern);

Console.WriteLine(isValid); // True

このパターンは、空白や@を含まない文字列、@、ドメイン部分、ドット、末尾部分という形を簡易的に確認します。

もう少し制限を加えるなら、次のように英数字や記号を明示できます。

C#
string pattern = @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$";

使用例です。

C#
static bool IsEmail(string value)
{
return Regex.IsMatch(value, @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$");
}

ただし、このパターンでもすべての正しいメールアドレス仕様を完全に網羅するわけではありません。Webフォームなどでは「一般的なメールアドレス形式の簡易チェック」として使うのが現実的です。

5-2. 電話番号をチェックする

日本の電話番号をハイフンありで簡易チェックする例です。

C#
string phone = "090-1234-5678";
string pattern = @"^\d{2,4}-\d{2,4}-\d{4}$";

bool isValid = Regex.IsMatch(phone, pattern);

Console.WriteLine(isValid); // True

携帯電話番号に限定する場合は、次のようにできます。

C#
string pattern = @"^0[789]0-\d{4}-\d{4}$";

ハイフンなしも許可したい場合は、-?を使います。

C#
string pattern = @"^0[789]0-?\d{4}-?\d{4}$";

使用例です。

C#
static bool IsMobilePhone(string value)
{
return Regex.IsMatch(value, @"^0[789]0-?\d{4}-?\d{4}$");
}

電話番号は国番号、固定電話、IP電話、フリーダイヤルなど形式が多いため、実務では許可したい形式を明確にしてからパターンを決めましょう。

5-3. 郵便番号をチェックする

日本の郵便番号は、一般的に123-4567の形式です。

C#
string zipCode = "123-4567";
bool isValid = Regex.IsMatch(zipCode, @"^\d{3}-\d{4}$");

Console.WriteLine(isValid); // True

ハイフンなしも許可する場合は、次のように書けます。

C#
bool isValid = Regex.IsMatch(zipCode, @"^\d{3}-?\d{4}$");

メソッド化すると使いやすくなります。

C#
static bool IsZipCode(string value)
{
return Regex.IsMatch(value, @"^\d{3}-?\d{4}$");
}

郵便番号の形式だけを確認したい場合はRegexで十分ですが、実在する郵便番号かどうかまで確認するには郵便番号データとの照合が必要です。

5-4. URLを抽出する

文字列からURLを抽出する例です。

C#
string text = "公式サイトは https://example.com です。参考: http://test.jp/page";
string pattern = @"https?://[^\s]+";

MatchCollection matches = Regex.Matches(text, pattern);

foreach (Match match in matches)
{
Console.WriteLine(match.Value);
}

実行結果は次のようになります。

https://example.com
http://test.jp/page

https?は、httpまたはhttpsに一致します。[^\s]+は、空白以外の文字が1文字以上続くことを表します。

より実務的には、句読点や閉じ括弧がURLの末尾に含まれてしまうケースがあります。その場合は、許可する文字を調整します。

C#
string pattern = @"https?://[a-zA-Z0-9\-._~:/?#\[\]@!$&'()*+,;=%]+";

厳密なURL検証が必要な場合は、Uri.TryCreateなどと組み合わせるとよいでしょう。

5-5. 数字だけを取り出す

文字列から数字だけを取り出すには、数字以外を削除します。

C#
string input = "注文番号: A-123-456";
string numbers = Regex.Replace(input, @"\D", "");

Console.WriteLine(numbers); // 123456

\Dは、数字以外の文字を表します。

複数の数値を別々に取り出したい場合は、Matchesを使います。

C#
string input = "価格: 1200円, 数量: 3個";
MatchCollection matches = Regex.Matches(input, @"\d+");

foreach (Match match in matches)
{
Console.WriteLine(match.Value);
}

実行結果は次のようになります。

1200
3

「すべての数字を連結して取り出す」のか、「数値ごとに抽出する」のかによって、ReplaceMatchesを使い分けましょう。

5-6. 英数字のみ許可する

英数字のみを許可する入力チェックです。

C#
string input = "abc123";
bool isValid = Regex.IsMatch(input, @"^[a-zA-Z0-9]+$");

Console.WriteLine(isValid); // True

空文字を許可したい場合は、+ではなく*を使います。

C#
bool isValid = Regex.IsMatch(input, @"^[a-zA-Z0-9]*$");

アンダースコアも許可する場合は、次のようにします。

C#
bool isValid = Regex.IsMatch(input, @"^[a-zA-Z0-9_]+$");

ユーザーIDや商品コードの入力チェックでは、許可する文字を明示することが重要です。

C#
static bool IsUserId(string value)
{
return Regex.IsMatch(value, @"^[a-zA-Z0-9_]{4,20}$");
}

この例では、英数字とアンダースコアを許可し、4文字以上20文字以下に制限しています。

5-7. 日付形式をチェックする

yyyy/MM/dd形式の日付をチェックする例です。

C#
string date = "2026/06/14";
string pattern = @"^\d{4}/\d{2}/\d{2}$";

bool isValid = Regex.IsMatch(date, pattern);

Console.WriteLine(isValid); // True

ただし、この正規表現は「形式」だけを確認します。たとえば、2026/99/99のような実在しない日付でも一致してしまいます。

実在する日付かどうかまで確認したい場合は、DateTime.TryParseExactと組み合わせるのがおすすめです。

C#
using System.Globalization;

string input = "2026/06/14";

bool isValid = DateTime.TryParseExact(
input,
"yyyy/MM/dd",
CultureInfo.InvariantCulture,
DateTimeStyles.None,
out DateTime date
);

Console.WriteLine(isValid);

Regexは形式チェック、DateTime.TryParseExactは日付としての妥当性チェック、というように役割を分けると安全です。

5-8. CSVやログから特定の値を抽出する

ログ文字列から日時、レベル、メッセージを抽出する例です。

C#
string log = "2026-06-14 10:30:45 [ERROR] File not found";
string pattern = @"^(?<date>\d{4}-\d{2}-\d{2}) (?<time>\d{2}:\d{2}:\d{2}) \[(?<level>[A-Z]+)\] (?<message>.+)$";

Match match = Regex.Match(log, pattern);

if (match.Success)
{
Console.WriteLine(match.Groups["date"].Value);
Console.WriteLine(match.Groups["time"].Value);
Console.WriteLine(match.Groups["level"].Value);
Console.WriteLine(match.Groups["message"].Value);
}

名前付きグループを使うと、抽出した値の意味がわかりやすくなります。

簡単なCSV風の文字列から値を取り出す例も見てみましょう。

C#
string line = "1001,Tanaka,Tokyo";
string pattern = @"^(?<id>\d+),(?<name>[^,]+),(?<city>[^,]+)$";

Match match = Regex.Match(line, pattern);

if (match.Success)
{
Console.WriteLine(match.Groups["id"].Value);
Console.WriteLine(match.Groups["name"].Value);
Console.WriteLine(match.Groups["city"].Value);
}

ただし、本格的なCSVはダブルクォートや改行を含む場合があり、正規表現だけで正確に処理するのは難しいです。実務ではCSVライブラリの利用も検討しましょう。

5-9. HTMLタグを削除・置換する

HTMLタグを簡易的に削除する例です。

C#
string html = "<p>Hello <strong>C# Regex</strong></p>";
string text = Regex.Replace(html, @"<.*?>", "");

Console.WriteLine(text); // Hello C# Regex

.*?は最短一致を表します。.*だけにすると、想定より広く一致してしまうことがあるため注意が必要です。

タグを別の文字列に置換することもできます。

C#
string result = Regex.Replace(html, @"<br\s*/?>", "\n", RegexOptions.IgnoreCase);

ただし、HTMLは正規表現だけで完全に解析するのが難しい構造です。単純なタグ削除であればRegexでも対応できますが、複雑なHTMLを扱う場合はHTMLパーサーを使うほうが安全です。

5-10. 全角・半角や日本語を含む入力チェックを行う

日本語を含む名前の入力チェック例です。

C#
string name = "山田太郎";
string pattern = @"^[\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FFF]+$";

bool isValid = Regex.IsMatch(name, pattern);

Console.WriteLine(isValid); // True

全角カタカナのみを許可する場合は次のようにします。

C#
bool isValid = Regex.IsMatch("ヤマダタロウ", @"^[\u30A0-\u30FF]+$");

半角英数字のみを許可する場合は次のようにします。

C#
bool isValid = Regex.IsMatch("abc123", @"^[a-zA-Z0-9]+$");

全角英数字や記号をどう扱うかは、システムの要件によって変わります。たとえば、氏名入力では漢字、ひらがな、カタカナ、長音、スペースを許可することが多いです。

C#
string pattern = @"^[\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FFFー\s ]+$";

入力チェックでは、「何を禁止するか」よりも「何を許可するか」を考えると、安全でわかりやすいパターンになります。

6. グループ化・キャプチャ・置換を使いこなす

C# Regexを実務で使ううえで重要なのが、グループ化とキャプチャです。グループ化を使うと、正規表現に一致した文字列の一部だけを取り出したり、置換時に再利用したりできます。

たとえば、メールアドレスからユーザー名とドメインを分けて取得したり、日付の年月日を並び替えたりできます。

6-1. ()で一致した部分をグループ化する

正規表現では、() を使ってパターンの一部をグループ化できます。

C#
string input = "2026-06-14";
string pattern = @"(\d{4})-(\d{2})-(\d{2})";

Match match = Regex.Match(input, pattern);

if (match.Success)
{
Console.WriteLine(match.Groups[1].Value); // 2026
Console.WriteLine(match.Groups[2].Value); // 06
Console.WriteLine(match.Groups[3].Value); // 14
}

Groups[0]には一致全体が入ります。Groups[1]以降に、括弧でキャプチャした値が順番に入ります。

C#
Console.WriteLine(match.Groups[0].Value); // 2026-06-14

グループ化は、抽出だけでなく、|による選択範囲をまとめる場合にも使います。

C#
bool result = Regex.IsMatch("cat", @"^(cat|dog|bird)$");

6-2. Groupsでキャプチャした値を取得する

Groupsを使うと、キャプチャした部分文字列を取得できます。

C#
string input = "Name: Tanaka, Age: 30";
string pattern = @"Name: (\w+), Age: (\d+)";

Match match = Regex.Match(input, pattern);

if (match.Success)
{
string name = match.Groups[1].Value;
string age = match.Groups[2].Value;

Console.WriteLine(name); // Tanaka
Console.WriteLine(age); // 30
}

キャプチャグループは便利ですが、番号だけで管理すると、正規表現が複雑になったときに読みづらくなります。

C#
match.Groups[1].Value
match.Groups[2].Value
match.Groups[3].Value

このようなコードは、あとから見たときに何を取り出しているのかわかりにくくなります。そこで、次に紹介する名前付きグループを使うと、より保守しやすくなります。

6-3. 名前付きグループでコードを読みやすくする

名前付きグループは、(?<name>...)の形式で書きます。

C#
string input = "2026-06-14";
string pattern = @"(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})";

Match match = Regex.Match(input, pattern);

if (match.Success)
{
Console.WriteLine(match.Groups["year"].Value); // 2026
Console.WriteLine(match.Groups["month"].Value); // 06
Console.WriteLine(match.Groups["day"].Value); // 14
}

名前付きグループを使うと、コードの意味が明確になります。

ログ解析のように複数の値を抽出する処理では、特に効果的です。

C#
string log = "2026-06-14 10:30:45 [WARN] Disk space low";
string pattern = @"(?<date>\d{4}-\d{2}-\d{2}) (?<time>\d{2}:\d{2}:\d{2}) \[(?<level>\w+)\] (?<message>.+)";

Match match = Regex.Match(log, pattern);

if (match.Success)
{
Console.WriteLine(match.Groups["date"].Value);
Console.WriteLine(match.Groups["time"].Value);
Console.WriteLine(match.Groups["level"].Value);
Console.WriteLine(match.Groups["message"].Value);
}

6-4. 後方参照を使って同じ文字列の繰り返しを検出する

後方参照を使うと、以前にキャプチャした文字列と同じ文字列に一致させることができます。

たとえば、同じ単語が連続しているかを検出する例です。

C#
string input = "This is is a test.";
string pattern = @"\b(\w+)\s+\1\b";

Match match = Regex.Match(input, pattern);

if (match.Success)
{
Console.WriteLine(match.Value); // is is
}

\1は、1番目のキャプチャグループと同じ文字列を表します。

名前付きグループを使った後方参照もできます。

C#
string pattern = @"\b(?<word>\w+)\s+\k<word>\b";

HTMLの開始タグと終了タグの名前が一致しているかを簡易的に見る例です。

C#
string input = "<h1>Title</h1>";
string pattern = @"<(?<tag>\w+)>.*</\k<tag>>";

bool result = Regex.IsMatch(input, pattern);
Console.WriteLine(result); // True

後方参照は便利ですが、複雑に使いすぎると正規表現が読みづらくなるため、必要な場面に絞って使いましょう。

6-5. Replaceでキャプチャした値を使って置換する

Regex.Replaceでは、キャプチャした値を置換後の文字列で再利用できます。

たとえば、yyyy-MM-ddyyyy/MM/ddに変換する例です。

C#
string input = "2026-06-14";
string result = Regex.Replace(input, @"(\d{4})-(\d{2})-(\d{2})", "$1/$2/$3");

Console.WriteLine(result); // 2026/06/14

$1$2$3は、それぞれ1番目、2番目、3番目のキャプチャグループを表します。

名前付きグループを使った置換もできます。

C#
string input = "2026-06-14";
string pattern = @"(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})";
string result = Regex.Replace(input, pattern, "${year}/${month}/${day}");

Console.WriteLine(result); // 2026/06/14

電話番号の表示形式を変える例です。

C#
string input = "09012345678";
string result = Regex.Replace(input, @"(\d{3})(\d{4})(\d{4})", "$1-$2-$3");

Console.WriteLine(result); // 090-1234-5678

6-6. Regex.ReplaceとMatchEvaluatorで柔軟に置換する

単純な置換ではなく、一致した内容に応じて処理を変えたい場合は、MatchEvaluatorを使います。

たとえば、文字列内の数値を2倍にする例です。

C#
string input = "価格: 100円, 数量: 3";
string result = Regex.Replace(input, @"\d+", match =>
{
int number = int.Parse(match.Value);
return (number * 2).ToString();
});

Console.WriteLine(result); // 価格: 200円, 数量: 6

一致した文字列を見ながら動的に置換できるため、通常の置換文字列では対応しにくい処理に向いています。

名前をマスクする例です。

C#
string input = "name=Tanaka; name=Suzuki;";
string result = Regex.Replace(input, @"name=(\w+)", match =>
{
string name = match.Groups[1].Value;
return $"name={name[0]}***";
});

Console.WriteLine(result); // name=T***; name=S***;

MatchEvaluatorを使うと柔軟性が高くなりますが、処理が複雑になりすぎる場合は、正規表現で抽出してから通常のC#コードで処理するほうが読みやすいこともあります。

7. RegexOptionsでマッチ条件を変更する

RegexOptionsを使うと、正規表現の動作を変更できます。大文字小文字を区別しない、複数行モードにする、改行を.に含める、コンパイルして高速化するなど、実務で役立つオプションが用意されています。

RegexOptionsは、Regex.IsMatchなどのメソッドの引数に指定できます。

C#
bool result = Regex.IsMatch("Hello", "hello", RegexOptions.IgnoreCase);

複数のオプションを組み合わせることもできます。

C#
var options = RegexOptions.IgnoreCase | RegexOptions.Multiline;

7-1. IgnoreCase:大文字・小文字を区別しない

RegexOptions.IgnoreCaseを使うと、大文字と小文字を区別せずに一致させられます。

C#
string input = "CSharp Regex";
bool result = Regex.IsMatch(input, "csharp", RegexOptions.IgnoreCase);

Console.WriteLine(result); // True

URLやコマンド、キーワードなど、大文字小文字を区別したくない場合に便利です。

C#
string input = "ERROR: File not found";
bool isError = Regex.IsMatch(input, @"^error", RegexOptions.IgnoreCase);

Console.WriteLine(isError); // True

ただし、カルチャによって大文字小文字の扱いが変わる可能性がある場面では、CultureInvariantも検討するとよいでしょう。

7-2. Multiline:複数行の先頭・末尾を扱う

RegexOptions.Multilineを使うと、^$が文字列全体ではなく、各行の先頭と末尾にも一致するようになります。

C#
string input = "INFO start\nERROR failed\nINFO end";
string pattern = @"^ERROR.*$";

Match match = Regex.Match(input, pattern, RegexOptions.Multiline);

if (match.Success)
{
Console.WriteLine(match.Value); // ERROR failed
}

ログ解析では、複数行の中から特定の行だけを取り出したいことがよくあります。そのような場合にMultilineが役立ちます。

Multilineを指定しない場合、^は文字列全体の先頭、$は文字列全体の末尾として扱われます。そのため、各行に対する検索では期待通りに一致しないことがあります。

7-3. Singleline:改行を含めて任意の文字に一致させる

RegexOptions.Singlelineを使うと、.が改行にも一致するようになります。

C#
string input = "<div>\nHello\n</div>";
string pattern = @"<div>.*</div>";

bool result = Regex.IsMatch(input, pattern, RegexOptions.Singleline);

Console.WriteLine(result); // True

通常、.は改行に一致しません。そのため、複数行にまたがるテキストを扱う場合は、Singlelineが必要になることがあります。

ただし、.*は広く一致しやすいため、必要に応じて最短一致の.*?を使います。

C#
string pattern = @"<div>.*?</div>";

SinglelineMultilineは名前が似ていますが、役割は異なります。Singleline.の挙動を変え、Multiline^$の挙動を変えます。

7-4. Compiled:繰り返し使う正規表現を高速化する

RegexOptions.Compiledを指定すると、正規表現をコンパイルして実行できるため、繰り返し使う場面でパフォーマンスが向上することがあります。

C#
var regex = new Regex(@"^\d{3}-\d{4}$", RegexOptions.Compiled);

bool result = regex.IsMatch("123-4567");

大量のデータに対して同じ正規表現を何度も使う場合は、Compiledが効果を発揮することがあります。

一方で、Compiledには初期化コストもあります。1回だけ使う正規表現や、頻繁にパターンが変わる処理では、必ずしも有利とは限りません。

つまり、RegexOptions.Compiledは「繰り返し使う固定パターン」に向いています。なんとなく毎回付けるのではなく、使う場面を選びましょう。

7-5. CultureInvariant:カルチャ依存を避ける

RegexOptions.CultureInvariantを使うと、カルチャに依存しない比較を行えます。

C#
bool result = Regex.IsMatch(
"FILE",
"file",
RegexOptions.IgnoreCase | RegexOptions.CultureInvariant
);

大文字小文字を区別しない比較では、カルチャによって結果が変わる可能性があります。ユーザーの表示言語や地域設定に影響されたくない場合は、CultureInvariantを使うと意図が明確になります。

特に、システム内部の識別子、ログレベル、プロトコル名、固定キーワードなどを扱う場合は、カルチャに依存しないほうが安全です。

C#
string input = "error";
bool isError = Regex.IsMatch(
input,
@"^ERROR$",
RegexOptions.IgnoreCase | RegexOptions.CultureInvariant
);

7-6. 複数のRegexOptionsを組み合わせる方法

複数のRegexOptionsは、ビットOR演算子|で組み合わせます。

C#
var options = RegexOptions.IgnoreCase | RegexOptions.Multiline;

string input = "INFO start\nerror failed";
bool result = Regex.IsMatch(input, @"^ERROR", options);

Console.WriteLine(result); // True

Regexインスタンスを作るときにも指定できます。

C#
var regex = new Regex(
@"^ERROR.*$",
RegexOptions.IgnoreCase | RegexOptions.Multiline
);

Match match = regex.Match("info\nerror failed\nend");

if (match.Success)
{
Console.WriteLine(match.Value);
}

よく使う組み合わせとしては、ログ解析でIgnoreCase | Multiline、複数行HTML風テキスト処理でSingleline | IgnoreCase、固定パターンの大量処理でCompiled | CultureInvariantなどがあります。

8. C# Regexでよくあるエラーと解決方法

C# Regexでは、正規表現そのもののミスだけでなく、C#の文字列リテラルの書き方によるミスもよく起こります。ここでは、初心者がつまずきやすいエラーや、実務で起こりがちなトラブルを解説します。

問題が起きたときは、まず「C#の文字列として正しいか」「正規表現として正しいか」「部分一致と全体一致を混同していないか」を確認しましょう。

8-1. 「\dが使えない」原因はエスケープ不足

C#で次のように書くと、エラーになります。

C#
string pattern = "\d+";

これは、C#の通常文字列で\dが正しいエスケープシーケンスではないためです。

正しくは、@""を使います。

C#
string pattern = @"\d+";

または、バックスラッシュをエスケープします。

C#
string pattern = "\\d+";

C# Regexでは、基本的に@"..."で正規表現パターンを書くと覚えておくとよいでしょう。

C#
bool result = Regex.IsMatch("abc123", @"\d+");

ただし、@""の中でダブルクォートを使いたい場合は、""と2つ重ねる必要があります。

C#
string pattern = @"name=""([^""]+)""";

8-2. 思ったより広く一致してしまう原因と最短一致

正規表現でよくある失敗が、.*によって思ったより広く一致してしまうケースです。

C#
string input = "<p>one</p><p>two</p>";
string result = Regex.Match(input, @"<p>.*</p>").Value;

Console.WriteLine(result); // <p>one</p><p>two</p>

.*は可能な限り長く一致しようとするため、最初の<p>から最後の</p>まで一致してしまいます。

このような場合は、最短一致の.*?を使います。

C#
string result = Regex.Match(input, @"<p>.*?</p>").Value;

Console.WriteLine(result); // <p>one</p>

*+{n,m}などは通常、貪欲に一致します。必要以上に広く一致する場合は、*?+?{n,m}?のような最短一致を検討しましょう。

8-3. ^と$が期待通りに動かない原因

^$は、通常は文字列全体の先頭と末尾を表します。

C#
bool result = Regex.IsMatch("abc123", @"^\d+$");
Console.WriteLine(result); // False

複数行の各行に対して先頭や末尾を判定したい場合は、RegexOptions.Multilineが必要です。

C#
string input = "INFO start\nERROR failed\nINFO end";
string pattern = @"^ERROR.*$";

Match match = Regex.Match(input, pattern, RegexOptions.Multiline);

Console.WriteLine(match.Value); // ERROR failed

また、入力文字列の末尾に改行が含まれている場合も、期待と異なる結果になることがあります。フォーム入力やファイル読み込みでは、前後の空白や改行をTrimで取り除くことも検討しましょう。

C#
string input = "12345\n";
bool result = Regex.IsMatch(input.Trim(), @"^\d+$");

8-4. Matchしているのに値が取得できない原因

Regex.Matchを使ったとき、一致していないのにValueを見てしまうと、空文字が返ります。

C#
Match match = Regex.Match("abc", @"\d+");
Console.WriteLine(match.Value); // 空文字

値を取得する前に、必ずSuccessを確認しましょう。

C#
Match match = Regex.Match("abc", @"\d+");

if (match.Success)
{
Console.WriteLine(match.Value);
}
else
{
Console.WriteLine("一致しませんでした");
}

また、グループの番号を間違えているケースもあります。

C#
string input = "2026-06-14";
Match match = Regex.Match(input, @"(\d{4})-(\d{2})-(\d{2})");

Console.WriteLine(match.Groups[0].Value); // 全体
Console.WriteLine(match.Groups[1].Value); // 年
Console.WriteLine(match.Groups[2].Value); // 月
Console.WriteLine(match.Groups[3].Value); // 日

Groups[0]は一致全体であり、最初の括弧ではない点に注意しましょう。

8-5. 日本語が一致しないときの確認ポイント

日本語が正規表現に一致しない場合は、まず文字範囲を確認しましょう。

たとえば、ひらがなだけを許可するパターンでは、漢字やカタカナは一致しません。

C#
Regex.IsMatch("山田", @"^[\u3040-\u309F]+$"); // False

漢字も許可したい場合は、漢字の範囲を追加します。

C#
Regex.IsMatch("山田", @"^[\u3040-\u309F\u4E00-\u9FFF]+$"); // True

カタカナには全角カタカナと半角カタカナがあります。全角カタカナの範囲だけでは、半角カタカナに一致しません。

C#
Regex.IsMatch("カタカナ", @"^[\u30A0-\u30FF]+$"); // False

全角スペースと半角スペースの違いにも注意が必要です。

C#
string pattern = @"^[\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FFF\s ]+$";

最後の は全角スペースです。日本語入力では全角・半角の違いが原因で一致しないことがあるため、許可する文字を明確にしましょう。

8-6. 正規表現が遅い・処理が止まるときの原因

正規表現が遅い、または処理が止まったように見える場合、複雑なパターンによるバックトラッキングが原因のことがあります。

特に、次のようなパターンには注意が必要です。

C#
^(a+)+$

このようなネストした繰り返しは、入力によっては非常に時間がかかることがあります。

対策としては、正規表現を単純にする、曖昧な.*を減らす、入力文字数を制限する、タイムアウトを設定する、といった方法があります。

C#
var regex = new Regex(@"^\d+$", RegexOptions.None, TimeSpan.FromSeconds(1));

bool result = regex.IsMatch("12345");

外部から入力される文字列に対して複雑なRegexを使う場合は、タイムアウトを設定しておくと安全です。

9. パフォーマンスと安全性を意識したRegexの使い方

Regexは便利ですが、使い方によってはパフォーマンスや安全性の問題につながることがあります。特に、ユーザー入力に対して複雑な正規表現を実行する場合や、大量データを処理する場合は注意が必要です。

ここでは、実務でC# Regexを安全かつ効率的に使うためのポイントを解説します。

9-1. 同じ正規表現を何度も使うならRegexインスタンスを再利用する

同じ正規表現を何度も使う場合は、毎回静的メソッドを呼び出すのではなく、Regexインスタンスを作って再利用するとコードが整理されます。

C#
private static readonly Regex ZipCodeRegex = new Regex(@"^\d{3}-\d{4}$");

static bool IsZipCode(string value)
{
return ZipCodeRegex.IsMatch(value);
}

ループ内で毎回Regexオブジェクトを作るのは避けましょう。

C#
foreach (var item in items)
{
var regex = new Regex(@"^\d+$"); // 毎回作成される
if (regex.IsMatch(item))
{
Console.WriteLine(item);
}
}

次のように、ループの外で作成して再利用するほうがよいです。

C#
var regex = new Regex(@"^\d+$");

foreach (var item in items)
{
if (regex.IsMatch(item))
{
Console.WriteLine(item);
}
}

同じパターンを繰り返し使う場面では、Regexの再利用を意識しましょう。

9-2. RegexOptions.Compiledを使うべき場面・避けるべき場面

RegexOptions.Compiledは、正規表現をコンパイルして実行するオプションです。繰り返し実行する固定パターンでは高速化が期待できます。

C#
private static readonly Regex EmailRegex = new Regex(
@"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$",
RegexOptions.Compiled
);

ただし、Compiledには初期化コストがあります。そのため、次のようなケースでは避けたほうがよいことがあります。

1回しか使わない正規表現、ユーザー入力によってパターンが頻繁に変わる正規表現、アプリケーション起動時の負荷を増やしたくない場合です。

実務では、まず通常のRegexで実装し、パフォーマンス上の問題が確認できた場合にCompiledを検討するのが無難です。

9-3. Regexのタイムアウトを設定して処理停止を防ぐ

ユーザー入力に対してRegexを実行する場合は、タイムアウトを設定することが重要です。

C#
var regex = new Regex(
@"^(a+)+$",
RegexOptions.None,
TimeSpan.FromMilliseconds(500)
);

try
{
bool result = regex.IsMatch("aaaaaaaaaaaaaaaaaaaa!");
}
catch (RegexMatchTimeoutException)
{
Console.WriteLine("正規表現の処理がタイムアウトしました");
}

タイムアウトを設定しておくと、想定外に時間がかかる入力が来ても、処理を止めることができます。

WebアプリケーションやAPIでは、外部から任意の文字列が送られてきます。複雑な正規表現を使う場合は、ReDoSと呼ばれる正規表現の過剰なバックトラッキングによる攻撃にも注意が必要です。

対策として、入力文字数の制限、単純なパターン設計、タイムアウト設定を組み合わせると安全性が高まります。

9-4. 複雑すぎる正規表現を避ける設計の考え方

正規表現は強力ですが、複雑にしすぎると保守が難しくなります。

たとえば、1つの正規表現でメールアドレス、日付、URL、タグ構造などをすべて処理しようとすると、読みづらく、バグを見つけにくいコードになります。

複雑になりそうな場合は、次のように考えましょう。

まずRegexで大まかに抽出し、その後C#コードで細かく検証する。形式チェックと意味チェックを分ける。コメントや名前付きグループを使って意図を明確にする。長すぎる正規表現は分割する。専用パーサーや標準APIがある場合はRegexにこだわらない。

たとえば日付の場合、Regexだけで完全に妥当性を判定するより、DateTime.TryParseExactを使うほうが安全です。

C#
if (Regex.IsMatch(input, @"^\d{4}/\d{2}/\d{2}$") &&
DateTime.TryParseExact(input, "yyyy/MM/dd", null, System.Globalization.DateTimeStyles.None, out _))
{
Console.WriteLine("有効な日付です");
}

Regexは万能ではありません。読みやすさと安全性を優先しましょう。

9-5. GeneratedRegex属性を使った最新の書き方

.NET 7以降では、GeneratedRegex属性を使って正規表現をソース生成する書き方が利用できます。固定の正規表現を使う場合、パフォーマンスや起動時コストの面で有利になることがあります。

C#
using System.Text.RegularExpressions;

partial class Program
{
[GeneratedRegex(@"^\d{3}-\d{4}$")]
private static partial Regex ZipCodeRegex();

static void Main()
{
Console.WriteLine(ZipCodeRegex().IsMatch("123-4567")); // True
}
}

GeneratedRegexを使うには、partialメソッドとしてRegexを返すメソッドを定義します。

オプションを指定することもできます。

C#
[GeneratedRegex(@"^error", RegexOptions.IgnoreCase)]
private static partial Regex ErrorRegex();

固定パターンをアプリケーション内で繰り返し使う場合は、new Regex(..., RegexOptions.Compiled)だけでなく、GeneratedRegexも選択肢になります。

ただし、使用できる.NETのバージョンやプロジェクト設定によって書き方が変わるため、既存プロジェクトではターゲットフレームワークを確認しましょう。

9-6. 入力検証でRegexだけに頼りすぎない注意点

入力検証でRegexは便利ですが、Regexだけで安全性を保証できるわけではありません。

メールアドレスの形式が正しくても、実際に存在するアドレスかどうかはわかりません。日付形式が正しくても、実在する日付かどうかは別のチェックが必要です。URL形式に見えても、安全なリンクかどうかは別問題です。

たとえば、メールアドレスはRegexで簡易チェックした後、確認メールを送ることで実在性を確認できます。

日付はRegexで形式を確認した後、DateTime.TryParseExactで妥当性を確認できます。

数値はRegexで数字だけか確認するより、int.TryParsedecimal.TryParseを使ったほうが適切な場合もあります。

C#
if (int.TryParse(input, out int number))
{
Console.WriteLine($"数値です: {number}");
}

Regexは「文字列の形」を見るのが得意です。しかし、業務ルール、存在確認、セキュリティチェックまでRegexだけで済ませようとしないことが重要です。

10. C# Regexを学ぶための練習問題

C# Regexを身につけるには、実際にパターンを書いて試すのが一番です。ここでは、基本的な練習問題と解答例を紹介します。

サンプルをそのまま写すだけでなく、条件を少し変えて試してみると理解が深まります。たとえば、ハイフンを任意にする、英数字の文字数制限を追加する、日本語も許可する、といった変更を加えてみましょう。

10-1. 数字だけの文字列か判定する

問題です。文字列が数字だけで構成されているか判定してください。

解答例です。

C#
string input = "12345";
bool result = Regex.IsMatch(input, @"^\d+$");

Console.WriteLine(result); // True

^$を使うことで、文字列全体が数字だけかを確認しています。

次のように、英字が混ざるとfalseになります。

C#
Console.WriteLine(Regex.IsMatch("123abc", @"^\d+$")); // False

空文字も許可したい場合は、+ではなく*を使います。

C#
bool result = Regex.IsMatch("", @"^\d*$");

ただし、入力チェックでは空文字を許可するかどうかを明確に決めておきましょう。

10-2. メールアドレスからドメインを抽出する

問題です。メールアドレスからexample.comのようなドメイン部分を抽出してください。

解答例です。

C#
string email = "user@example.com";
string pattern = @"^[^@\s]+@(?<domain>[^@\s]+)$";

Match match = Regex.Match(email, pattern);

if (match.Success)
{
Console.WriteLine(match.Groups["domain"].Value); // example.com
}

名前付きグループdomainを使って、@以降を取得しています。

ユーザー名部分も取得したい場合は、次のようにできます。

C#
string pattern = @"^(?<user>[^@\s]+)@(?<domain>[^@\s]+)$";
C#
Console.WriteLine(match.Groups["user"].Value);
Console.WriteLine(match.Groups["domain"].Value);

10-3. 文字列内の連続した空白を1つに置換する

問題です。文字列内の連続した空白を1つの半角スペースに置換してください。

解答例です。

C#
string input = "C#   Regex\t入門\nサンプル";
string result = Regex.Replace(input, @"\s+", " ");

Console.WriteLine(result); // C# Regex 入門 サンプル

\s+は、1文字以上の空白文字に一致します。半角スペース、タブ、改行などをまとめて置換できます。

前後の空白も削除したい場合は、Trimを組み合わせます。

C#
string result = Regex.Replace(input, @"\s+", " ").Trim();

半角スペースだけをまとめたい場合は、次のようにします。

C#
string result = Regex.Replace(input, @"[ ]+", " ");

10-4. ログ文字列から日時とエラーメッセージを取得する

問題です。次のログ文字列から日時、ログレベル、メッセージを取得してください。

2026-06-14 10:30:45 [ERROR] File not found

解答例です。

C#
string log = "2026-06-14 10:30:45 [ERROR] File not found";

string pattern = @"^(?<datetime>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) \[(?<level>[A-Z]+)\] (?<message>.+)$";

Match match = Regex.Match(log, pattern);

if (match.Success)
{
Console.WriteLine(match.Groups["datetime"].Value);
Console.WriteLine(match.Groups["level"].Value);
Console.WriteLine(match.Groups["message"].Value);
}

実行結果は次のようになります。

2026-06-14 10:30:45
ERROR
File not found

ログ形式が固定されている場合、Regexは非常に便利です。ただし、ログ形式が複数ある場合は、複数のパターンに分けるか、ログパーサーを使うことも検討しましょう。

10-5. 正規表現パターンを自分で改善してみる

最後の練習問題です。次の郵便番号チェックを改善してみましょう。

C#
Regex.IsMatch(input, @"\d{3}-\d{4}");

このパターンは、文字列の一部に郵便番号形式が含まれていれば一致します。

C#
Regex.IsMatch("abc123-4567xyz", @"\d{3}-\d{4}"); // True

入力値全体が郵便番号形式か確認したい場合は、^$を追加します。

C#
Regex.IsMatch(input, @"^\d{3}-\d{4}$");

ハイフンなしも許可したい場合は、次のようにできます。

C#
Regex.IsMatch(input, @"^\d{3}-?\d{4}$");

このように、正規表現は少しの違いで意味が変わります。「部分一致でよいのか」「全体一致にしたいのか」「省略可能な文字はあるのか」を意識して改善していきましょう。

11. C# Regexのチートシート

最後に、C# Regexでよく使うメソッド、正規表現記号、RegexOptions、入力チェック用パターン、エスケープが必要な文字をまとめます。

実務では、最初からすべてを暗記する必要はありません。よく使うパターンをチートシートとして確認しながら、少しずつ慣れていきましょう。

11-1. よく使うRegexメソッド早見表

Regex.IsMatchは、文字列がパターンに一致するか判定します。

C#
Regex.IsMatch("abc123", @"\d+");

Regex.Matchは、最初に一致した文字列を取得します。

C#
Match match = Regex.Match("abc123", @"\d+");

Regex.Matchesは、一致した文字列をすべて取得します。

C#
MatchCollection matches = Regex.Matches("A1 B2 C3", @"[A-Z]\d");

Regex.Replaceは、一致した文字列を置換します。

C#
string result = Regex.Replace("abc123", @"\d+", "#");

Regex.Splitは、正規表現に一致する箇所で分割します。

C#
string[] items = Regex.Split("a,b; c", @"[,;\s]+");

Regexインスタンスを作成して使うこともできます。

C#
var regex = new Regex(@"^\d+$");
bool result = regex.IsMatch("123");

11-2. よく使う正規表現記号早見表

数字1文字に一致します。

regex
\d

数字以外に一致します。

regex
\D

単語文字に一致します。

regex
\w

単語文字以外に一致します。

regex
\W

空白文字に一致します。

regex
\s

空白文字以外に一致します。

regex
\S

任意の1文字に一致します。

regex
.

0回以上の繰り返しです。

regex
*

1回以上の繰り返しです。

regex
+

0回または1回です。

regex
?

ちょうどn回です。

regex
{n}

n回以上m回以下です。

regex
{n,m}

文字列の先頭です。

regex
^

文字列の末尾です。

regex
$

指定した文字のいずれかです。

regex
[abc]

指定した文字以外です。

regex
[^abc]

いずれかのパターンに一致します。

regex
cat|dog

グループ化します。

regex
(...)

名前付きグループです。

regex
(?<name>...)

11-3. よく使うRegexOptions早見表

大文字小文字を区別しません。

C#
RegexOptions.IgnoreCase

複数行モードで^$を各行の先頭・末尾として扱います。

C#
RegexOptions.Multiline

.が改行にも一致するようになります。

C#
RegexOptions.Singleline

正規表現をコンパイルして実行します。

C#
RegexOptions.Compiled

カルチャに依存しない比較を行います。

C#
RegexOptions.CultureInvariant

複数のオプションは|で組み合わせます。

C#
RegexOptions.IgnoreCase | RegexOptions.Multiline

使用例です。

C#
bool result = Regex.IsMatch(
"ERROR\nfailed",
@"^error",
RegexOptions.IgnoreCase | RegexOptions.Multiline
);

11-4. 入力チェックでよく使うパターン早見表

数字のみです。

regex
^\d+$

英数字のみです。

regex
^[a-zA-Z0-9]+$

英数字とアンダースコアのみです。

regex
^[a-zA-Z0-9_]+$

郵便番号です。

regex
^\d{3}-\d{4}$

ハイフン任意の郵便番号です。

regex
^\d{3}-?\d{4}$

携帯電話番号の簡易チェックです。

regex
^0[789]0-?\d{4}-?\d{4}$

メールアドレスの簡易チェックです。

regex
^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$

URLの簡易抽出です。

regex
https?://[^\s]+

日付形式yyyy/MM/ddです。

regex
^\d{4}/\d{2}/\d{2}$

ひらがなのみです。

regex
^[\u3040-\u309F]+$

カタカナのみです。

regex
^[\u30A0-\u30FF]+$

漢字のみです。

regex
^[\u4E00-\u9FFF]+$

日本語の簡易チェックです。

regex
^[\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FFF]+$

11-5. エスケープが必要な文字一覧

正規表現では、次のような文字には特別な意味があります。

regex
. ^ $ * + ? ( ) [ ] { } \ | /

これらの文字そのものに一致させたい場合は、バックスラッシュでエスケープします。

ドット.に一致させる例です。

C#
Regex.IsMatch("example.com", @"\.");

括弧に一致させる例です。

C#
Regex.IsMatch("(test)", @"\(test\)");

バックスラッシュに一致させる例です。

C#
Regex.IsMatch(@"C:\Users", @"\\");

C#では、正規表現のエスケープに加えて、文字列リテラルとしてのエスケープも関係します。そのため、基本的には@""を使って書くのがおすすめです。

C#
string pattern = @"\d+\.\d+";

通常文字列で書く場合は、バックスラッシュを二重にする必要があります。

C#
string pattern = "\\d+\\.\\d+";

C# Regexでは、正規表現のエスケープとC#文字列のエスケープを混同しないことが重要です。

まとめ

C#で正規表現を使うには、System.Text.RegularExpressions.Regexクラスを利用します。csharp regexの基本は、入力文字列と正規表現パターンを指定し、IsMatchMatchMatchesReplaceSplitなどのメソッドを使い分けることです。

入力値が形式に一致するか判定したい場合はIsMatch、最初の一致を取得したい場合はMatch、すべての一致を取得したい場合はMatches、文字列を置換したい場合はReplace、正規表現で分割したい場合はSplitを使います。

また、C#でRegexを書くときは、@"\d+"のように逐語的文字列リテラルを使うと、バックスラッシュのエスケープでつまずきにくくなります。

正規表現では、\d\w\s.*+?{n,m}^$[]|などの基本記号を押さえることが重要です。さらに、グループ化や名前付きグループを使うと、ログ解析や値の抽出がしやすくなります。

実務では、メールアドレス、電話番号、郵便番号、URL、日付、日本語入力チェックなど、さまざまな場面でC# Regexが役立ちます。ただし、Regexだけですべてを厳密に検証しようとすると複雑になりすぎることがあります。日付ならDateTime.TryParseExact、数値ならTryParse、URLならUriクラスなど、標準APIと組み合わせることも大切です。

パフォーマンス面では、同じ正規表現を何度も使う場合はRegexインスタンスの再利用を検討しましょう。必要に応じてRegexOptions.CompiledGeneratedRegex属性を使うこともできます。また、外部入力に対して複雑な正規表現を使う場合は、タイムアウトを設定して安全性を高めることが重要です。

C# Regexは最初は難しく見えますが、基本パターンとメソッドを覚えれば、文字列処理を大きく効率化できます。まずはIsMatchで入力チェック、Matchで抽出、Replaceで置換という基本から練習し、少しずつグループ化やRegexOptionsへ進んでいきましょう。