C#のRegex.MatchとMatchesの違いを徹底解説!正規表現の使い方完全ガイド
生徒
「C#で、文章の中から特定の文字や数字だけを探し出したいのですが、何か良い方法はありますか?」
先生
「それなら正規表現という仕組みを使うのが一番ですね。C#にはRegex.MatchとRegex.Matchesという便利な機能がありますよ。」
生徒
「MatchとMatchesはどう違うんですか?どちらを使えばいいのか迷ってしまいそうです。」
先生
「一つだけ見つけたいのか、全部見つけたいのかという違いがあります。初心者の方にもわかりやすく、基本的な仕組みからじっくり解説していきますね!」
1. 正規表現(Regular Expression)とは何か?
プログラミングの世界には、正規表現(せいきひょうげん)という非常に便利な道具があります。これは、文字の並び方を「パターン」として表現する方法のことです。例えば、「メールアドレスの形式になっている文字を探す」とか、「文章の中から数字だけを抜き出す」といった複雑な検索が、たった一行のルール決めで実現できてしまいます。
パソコンを初めて触る方にとっては、魔法の呪文のように見えるかもしれません。しかし、仕組みはとても単純です。例えば、大量の書類の中から「〇〇市」で終わる住所だけを赤いペンで印をつける作業をイメージしてください。人間が手作業で行うと時間がかかりますが、プログラムにこのパターンを教えてあげれば、一瞬で終わらせることができます。C#というプログラミング言語では、この正規表現を扱うためにRegex(リジェックス)というクラスが用意されています。
2. Regex.Matchの役割と使い方を学ぼう
まず最初に紹介するのがRegex.Matchです。この機能の最大の特徴は、「最初に見つかった一つだけ」を報告してくれるという点です。たくさんの該当箇所があっても、最初に見つけた時点で探索を終了し、その結果を返します。
例えるなら、宝探しをしているときに「最初の一個を見つけたらすぐに報告してね」と頼まれているような状態です。特定のキーワードが含まれているかどうかを素早く確認したい場合や、文章の冒頭にある特定の情報を抜き出したい時に非常に重宝します。まずは、文字列の中から最初の数字を見つける簡単なプログラムを見てみましょう。
using System;
using System.Text.RegularExpressions;
class Program
{
static void Main()
{
string text = "私の誕生日は10月、友達は12月です。";
// \d+ は「1文字以上の数字」という意味のパターンです
Match result = Regex.Match(text, @"\d+");
if (result.Success)
{
Console.WriteLine("見つかった最初の数字: " + result.Value);
}
}
}
見つかった最初の数字: 10
このプログラムでは、「10」と「12」という二つの数字がありますが、Matchを使っているため、最初に見つかった「10」だけが表示されています。Successというのは「無事に見つかったかどうか」を表す合図です。
3. Regex.Matchesの役割と活用シーン
次に紹介するのがRegex.Matchesです。末尾に「es」がついている通り、これは複数形を意味します。つまり、「条件に合うものを全部まとめて見つけてくる」という機能です。文章の中に含まれるすべてのデータを抽出したい場合には、こちらを使います。
先ほどの宝探しの例えで言うなら、「この森にあるお宝を全部集めてきて」とお願いするようなものです。この場合、結果は一つではなく、リスト(名簿のようなもの)として返ってきます。そのため、見つかったものを順番に表示するために「繰り返し処理(foreach文)」と一緒に使うのが一般的です。次のコードで、すべての数字を抜き出す方法を確認しましょう。
using System;
using System.Text.RegularExpressions;
class Program
{
static void Main()
{
string text = "リンゴは150円、バナナは80円、メロンは1200円です。";
// 文章内のすべての数字を探します
MatchCollection results = Regex.Matches(text, @"\d+");
Console.WriteLine("見つかった件数: " + results.Count);
foreach (Match item in results)
{
Console.WriteLine("価格: " + item.Value + "円");
}
}
}
見つかった件数: 3
価格: 150円
価格: 80円
価格: 1200円
MatchCollectionというのは、見つかった結果を詰め込んだカゴのようなものです。foreachという命令を使うことで、カゴの中身を一つずつ取り出して画面に表示しています。すべての価格情報を抜き出すことができましたね。
4. MatchとMatchesを使い分ける判断基準
初心者の方が迷いやすいポイントは、「いつどちらを使えばいいのか」という点です。判断基準は非常にシンプルです。目的が「有無の確認」や「特定の一箇所」であればMatchを使い、「データの収集」や「一括処理」であればMatchesを選びます。
例えば、入力された電話番号が正しい形式かどうかをチェックするバリデーション(入力確認)では、一つでも正しい形式が見つかれば良いためMatchが適しています。一方で、長いニュース記事の中から「株式会社」という名前がつく組織名をすべてリストアップしたい場合は、取りこぼしがないようにMatchesを使う必要があります。このように、自分が最終的に何個のデータが欲しいのかを考えることが、プログラミングの上達への近道です。
5. よく使われる正規表現の記号(パターン)紹介
正規表現を使いこなすためには、文字のパターンを指定する「特殊な記号」を覚える必要があります。これらはプログラミング界の共通言語のようなものです。代表的なものをいくつか紹介します。
- \d : 任意の数字(0から9まで)を指します。
- \w : 英数字やアンダーバーを指します。
- + : 直前の文字が「1回以上繰り返される」ことを意味します。
- . (ドット) : どんな文字でも良い「任意の1文字」を指します。
- ^ : 行の先頭を指します。
例えば、先ほどのコードで使った\d+は、「数字が1個以上並んでいる場所」という意味になります。これを知っているだけで、郵便番号「\d{3}-\d{4}」のように、特定の形式をピンポイントで指定できるようになります。最初は難しく感じるかもしれませんが、パズルを組み合わせるような感覚で楽しんでみてください。
6. 実践!特定のキーワードを抽出するプログラム
今度はもう少し具体的な例として、テキストの中から「特定の形式のID」を探し出すプログラムを作ってみましょう。例えば、商品管理コードが「ID-数字」というルールで決まっている場合、それを効率よく抜き出す方法です。ここでは、Matchを使って特定の一つを詳しく調べる方法を紹介します。
using System;
using System.Text.RegularExpressions;
class Program
{
static void Main()
{
string input = "注文データ:受領済み、管理番号はID-7789です。";
// 「ID-」の後に数字が続くパターン
string pattern = @"ID-\d+";
Match m = Regex.Match(input, pattern);
if (m.Success)
{
Console.WriteLine("管理コードを検出しました。");
Console.WriteLine("抽出結果: " + m.Value);
}
else
{
Console.WriteLine("管理コードは見つかりませんでした。");
}
}
}
管理コードを検出しました。
抽出結果: ID-7789
このように、特定の接頭辞(この場合はID-)がついた情報を探すのは、実務でも非常によく使われるテクニックです。もし文章の中に複数のIDがあっても、Matchであれば一番最初に出てきた大切なIDだけを確実に捉えることができます。
7. 大文字と小文字を区別せずに検索する方法
正規表現を使う際、英字の大文字と小文字を区別したいときと、したくないときがあります。デフォルトでは厳密に区別されますが、オプションを指定することで柔軟な検索が可能になります。これは、ユーザーがどんな風に文字を入力するかわからない場合に非常に役立つ機能です。
例えば、「C#」という文字を探したいとき、相手が「c#」と小文字で書くかもしれません。そういった場合にRegexOptions.IgnoreCaseという設定を追加します。これにより、大文字・小文字の壁を越えて検索を行うことができます。
using System;
using System.Text.RegularExpressions;
class Program
{
static void Main()
{
string sample = "C# programming is fun. I love c#!";
// 第三引数に IgnoreCase を指定します
MatchCollection list = Regex.Matches(sample, "c#", RegexOptions.IgnoreCase);
Console.WriteLine("合計 " + list.Count + " 個のキーワードを発見しました。");
foreach (Match match in list)
{
Console.WriteLine("発見位置: " + match.Index + " 文字目");
}
}
}
合計 2 個のキーワードを発見しました。
発見位置: 0 文字目
発見位置: 30 文字目
このプログラムでは、最初の大文字「C#」と、後半の小文字「c#」の両方をしっかりと見つけることができています。match.Indexを使うことで、その文字が文章の最初から数えて何文字目にあるのかという位置情報も取得できるので、非常に高機能です。
8. エラーを防ぐための注意点と初心者がハマる罠
正規表現は強力ですが、初心者の方が間違いやすいポイントもいくつかあります。まず一つ目は、「パターンが見つからなかった時の処理」です。Matchの結果が空っぽなのに無理やりデータを取り出そうとすると、プログラムが止まってしまうことがあります。必ずif (result.Success)を使って、見つかったことを確認してから次の作業に移りましょう。
二つ目は、「@(アットマーク)」の付け忘れです。C#の文字列でバックスラッシュ(\)を扱う場合、文字列の先頭に「@」を付けることで、特殊な記号として正しく認識されるようになります。これを「逐次形式文字列リテラル」と呼びます。正規表現のパターンを書くときは、おまじないだと思って常に@""の形式で書く癖をつけておくと、余計なトラブルを防ぐことができます。
三つ目は、「欲張りな検索」です。例えば「.(ドット)」を使いすぎると、自分が意図したよりも長い範囲を検索結果として取ってきてしまうことがあります。最初はできるだけ具体的なパターン(例えば数字だけなら\d、英字だけなら[a-zA-Z]など)を指定するように心がけると、より正確なプログラムが書けるようになります。少しずつ慣れていき、正規表現の達人を目指しましょう!