C#で正規表現を利用するためのメソッド:特集:C#正規表現チートシート(1/2 ページ)
C#には正規表現を利用するためのRegexクラスが標準で用意されている。Regexクラスが提供するメソッドで正規表現を使用するための基本をまずは見てみよう。
C#に限らず多くのプログラミング言語には正規表現(Regular Expression)を利用するためのライブラリやパッケージが用意されている。正規表現を使うことで、強力なテキスト処理が可能になる。つまり何らかの文字列群の中から特定の「パターン」にマッチする部分を検索したり、文字列を置換したりできる。
なお、基本的には、正規表現はどんな言語でも同様に記述できるが、実際には言語やフレームワークごとに方言があったり、取り扱い方が異なったりする。本稿ではC#を対象に、その構成要素の基本を取り上げる。今回はSystem.Text.RegularExpression名前空間のRegexクラスが提供するIsMatch/Match/Matches/Replaceの各メソッドの使い方を見ながら、C#における正規表現のおおまかな概要を見ていこう。正規表現の詳細については次回以降に取り上げる。
C#の正規表現の基本
C#(というか.NET Framework)ではSystem.Text.RegularExpression名前空間のRegexクラスによって正規表現がサポートされている。これを使うことで、以下のようなことが可能になる。
- テキストが正規表現パターンにマッチするかどうかの判定
- テキストから正規表現パターンにマッチする部分を取得
- 正規表現パターンにマッチしたテキストの内容の置換
Regexクラスでは上から順番にIsMatchメソッド、Match/Matchesメソッド、Replaceメソッドでこれを行う。正規表現の話に入る前に、これらのメソッドについて簡単に見ながら、正規表現の基本についても見ておこう。なお、これらのメソッドのより具体的な使い方は.NET TIPSの以下の項目を参照されたい。
正規表現関連の.NET TIPS
IsMatchメソッド
例えば、「テキストが正規表現パターンにマッチするかどうかの判定」は以下のようにして行える。これは「空白文字が2文字以上連続しているかどうか」を判断するものだ。静的メソッドでは毎回正規表現パターンの解析が行われる。大量のテキストを処理したいといったときには、Regexオブジェクトを作成することで毎回の正規表現パターンの解析を行わずに済むようになる。
// 静的メソッドを使う場合
var text = "regular expression is so great!";
var pattern = @"\s\s+";
var match = Regex.IsMatch(text, pattern);
…… 省略 ……
// Regexオブジェクトを作成する場合
var text = "regular expression is so great!";
var pattern = @"\s\s+";
var regex = new Regex(pattern);
var match = regex.IsMatch(text);
…… 省略 ……
変数patternの内容が「正規表現パターン」だ。ここでは「\s\s+」を指定している。「\s」は「空白文字」を表す「メタ文字」(特殊な意味を持つ文字)と呼ばれるもので、半角/全角の空白文字や改行、タブ文字などを意味する*1。「+」は「1文字以上」を意味する「メタ文字」だ。よって、これは「空白文字の後に空白文字が1文字以上連続する」=「空白文字が2文字以上連続している」ことを意味する。
*1 より詳しくは空白文字を表す「文字クラス」の省略表記といえる。文字クラスとは「この中のどれかの文字」にマッチさせたい場合に、それらの文字を[]で囲んだもの。ここでは、空白文字としては空白文字やタブ文字、改行文字などのことであり、「\s」は[ \f\n\r\t\v]といった文字クラスを1文字で表現するメタ文字といえる(ただし、ここで示した文字クラスはあくまでも例である)。
上のコードでは、空白文字が2文字連続している部分と3文字連続している部分があるが、これらを「 」「 」「\s\s」「\s\s\s」などと別々に表現するのではなく、「\s\s+」とすることでまとめて表現できる。このように、正規表現を利用すると、テキストに含まれるさまざまな文字の並びを「パターン」としてひとまとめに扱える。これが正規表現では強力なテキスト処理が可能といわれるゆえんだ。
なお、変数patternが「@」記号で始まる逐語的文字列リテラルとなっているのは、正規表現ではバックスラッシュ記号(\)が多用されることから、これをエスケープして表現するのではなく、逐語的文字列リテラルで表現した方が簡潔に正規表現を記述できるからだ。
ただし、IsMatchメソッドはあくまでも変数textが変数patternで指定した正規表現パターンにマッチするかどうか(変数textの内容に、変数patternで指定した正規表現パターンが含まれているかどうか)を判定するだけで、どの部分がマッチしたかを取り出したり、その結果を使って何かの処理(具体的には置換)を行ったりすることはできない。このため、実際にはMatch/Matchesメソッドでマッチした部分を取得したり、Replaceメソッドでマッチしたテキストを何らかの形で置換したりすることになる。
IsMatchメソッドの詳しい使い方については「.NET TIPS:正規表現を使って文字列がパターンに一致するか調べるには?」を参照されたい。
いずれにせよ、C#で正規表現を使用するには、次のどちらかの方法が基本形となる。
- Regexクラスの静的メソッド(IsMatch/Match/Matches/Replaceなど)に、検索対象とテキストと正規表現パターン(とReplaceメソッドでは置換パターン)を渡す
- 正規表現パターンからRegexオブジェクトを作成し(new Regex("正規表現パターン"))、そのオブジェクトに対してIsMatch/Match/Matches/Replaceなどのメソッドを呼び出して、検索対象のテキスト(とReplaceメソッドでは置換パターン)を渡す
Matchメソッド/Matchesメソッド
MatchメソッドとMatchesメソッドは、テキストから正規表現パターンにマッチするものを検索する。Matchメソッドは最初に見つかったマッチをMatchオブジェクトとして返送する。後者はテキスト全体を検索して、マッチした部分を要素とするコレクションを返送する。これらのメソッドには静的メソッドもあるが、ここでは省略する。
ここでは、Matchesメソッドを見てみよう。以下は「Match method matches specified pattern from input text」というテキストから大文字小文字の区別なく「match」という語句を検索するものだ。
var text = "Match method matches specified pattern from input text";
var regex = new Regex(@"match", RegexOptions.IgnoreCase);
var matches = regex.Matches(text);
foreach (Match m in matches)
{
Console.WriteLine($"Found: {m.Value} at {m.Index}");
}
Matchesメソッドは、マッチした部分を表すMatchオブジェクトを要素とするMatchCollectionオブジェクトを返送する。上のコードでは、その各要素(Matchオブジェクト)について、マッチした内容(Valueプロパティ)と元のテキストにおける位置(Indexプロパティ)をコンソールに表示している。この他にもMatchオブジェクトには以下のようなプロパティがある。
プロパティ | 説明 |
---|---|
Captures | そのマッチにおけるキャプチャーのコレクション |
Groups | そのマッチにおけるグループのコレクション |
Length | マッチした文字列の長さ |
Success | マッチに成功したかどうか |
Name | キャプチャーグループの名前 |
Matchオブジェクトのプロパティ |
キャプチャーとグループについては後述するが、これらは正規表現中で「()」を使用することでその中にグループを形成し、そのグループに記述されている正規表現の内容にマッチする部分を後から参照できるように保存(キャプチャー)するためのものだ。
また、上ではRegexオブジェクトの作成時にオプションとしてRegexOptions.IgnoreCaseを指定している。読めば分かる通り、これは大文字小文字を無視することを意味する。Regexオブジェクトの作成時にはこの他にも以下のオプションを指定できる。
オプション | 説明 |
---|---|
Compiled | 正規表現をアセンブリにコンパイルすることで、実行時のパフォーマンスを向上させる(ただし、初期化に時間がかかるようになる) |
Multiline | 複数行モードを使用。このモードでは入力テキストの先頭を表すメタ文字「^」と入力テキストの末尾を表すメタ文字「$」が、各行の先頭と末尾を表すようになる |
Singleline | 単一行モードを使用。このモードでは、任意の1文字を表すメタ文字「.」が「改行文字を含む任意の1文字」にマッチするようになる |
ECMAScript | ECMAScript準拠の動作にする |
Regexコンストラクタに指定可能なオプション(一部) |
Matchesメソッドの詳しい使い方については「.NET TIPS:正規表現を使ってパターンに一致する全ての文字列を抽出するには?」を参照されたい。
一方、Matchメソッドでは最初に見つかったマッチだけが返送される。同じテキストから次のマッチを検索するにはMatchクラスのNextMatchメソッドを使用する。Matchメソッドで上と同じ処理を行うコードを以下に示す。
var text = "Match method matches specified pattern from input text";
var regex = new Regex(@"match", RegexOptions.IgnoreCase);
var m = regex.Match(text);
while (m.Success)
{
Console.WriteLine($"Found: {m.Value} at {m.Index}");
m = m.NextMatch();
}
なお、上のコードでは「RegexOptions.IgnoreCase」を指定して大文字小文字を区別しないようにしているが、メタ文字「|」を使うと以下のようにも記述できる。「|」はその文字で区切られた要素のいずれかとマッチする。
var text = "Match method matches specified pattern from input text";
var regex = new Regex(@"(M|m)atch");
var m = regex.Match(text);
while (m.Success)
{
Console.WriteLine($"Found: {m.Value} at {m.Index}");
m = m.NextMatch();
}
ここでは「(M|m)」としているので、これは「M」か「m」にマッチする。よって、全体としては「Match」か「match」にマッチすることになる。あるいは次のように記述してもよい。これは「文字クラス」を指定するものだ。
var text = "Match method matches specified pattern from input text";
var regex = new Regex(@"[Mm]atch");
var m = regex.Match(text);
while (m.Success)
{
Console.WriteLine($"Found: {m.Value} at {m.Index}");
m = m.NextMatch();
}
文字クラスは[]で囲まれた中に指定した文字のいずれかにマッチする。よって、これも「M」か「m」にマッチする。文字クラスの典型的な使用例としては「[a-zA-Z0-9]」でアルファベットの小文字/大文字/数字を指定するといったものがある。
Copyright© Digital Advantage Corp. All Rights Reserved.