ここでは.NET Frameworkの正規表現について基本をごく簡単に(主に正規表現パターンについて)説明します。なお.NET Frameworkの正規表現はPerl5の正規表現に対応するようにデザインされているということなので、Perlの正規表現を理解していれば問題ありません。
なお、「正規表現テストツール」を使って正規表現のテストを行うことができますので、お役立てください。
正規表現は、文字列を検索するために使用します。正規表現を使うと、かなり複雑な検索が可能です。正規表現を利用する主なケースには以下のようなものが挙げられます。
補足:これら以外にも、文字列を分割して配列にする場合にも使用できます。この場合は、Regex.Splitメソッドを使います。
「こんな文字列が出てくる部分を探して」ということを指定するには、それを表現したパターンを書く必要があります。適切なパターンを書けるようになることが、正規表現を勉強する最大の目標となるでしょう。
パターンは、ファイルの検索などで使用される「*」や「?」などのワイルドカードをご存じの方ならば、これと同じようなものだと思っていただいて結構です。
例えば、文字列からある郵便番号と一致する部分を探したいとします。その郵便番号が決まっており、「123-4567」であるならば、パターンは「123-4567」のままでOKです。ただし、このように探したい文字列が決まっているならば、正規表現を使う意味がありません。
決まった郵便番号ではなく、郵便番号っぽい文字列を探したい、つまり、「何らかの数字が3つ続き、-(ダッシュ)が挟まり、また数字が4つ続く文字列」を探したいということであれば、正規表現が役に立ちます。このような場合、書くべきパターンは、「\d\d\d-\d\d\d\d」となります(別の書き方もできます)。つまり、「\d」は「何らかの数字1文字」を意味します。
このように正規表現のパターンでは、「\」などの特定の文字列が特別な意味を持っています。このような特別な意味を持つ文字を「メタ文字」(メタキャラクタ)と呼びます。
.NETで正規表現を扱うには、Regexクラスを使います。以下にRegexクラスを使って文字列の検査、抽出、置換を行う簡単な例を示します。より詳しい例については、「正規表現を使って文字列がある形式と一致するか調べる」、「正規表現を使って文字列を検索し、抽出する」、「正規表現を使って文字列を置換する」をご覧ください。
'TextBox1に郵便番号っぽい文字列が含まれているか調べる If System.Text.RegularExpressions.Regex.IsMatch( _ TextBox1.Text, "\d\d\d-\d\d\d\d") Then Console.WriteLine("郵便番号が含まれています") End If 'TextBox1内の郵便番号っぽい文字列をすべて抽出する Dim mc As System.Text.RegularExpressions.MatchCollection = _ System.Text.RegularExpressions.Regex.Matches( _ TextBox1.Text, "\d\d\d-\d\d\d\d") For Each m As System.Text.RegularExpressions.Match In mc Console.WriteLine(m.Value) Next 'TextBox1内の郵便番号っぽい文字列の"-"を削除して、【】で囲む TextBox1.Text = System.Text.RegularExpressions.Regex.Replace( _ TextBox1.Text, "(\d\d\d)-(\d\d\d\d)", "【$1$2】")
//TextBox1に郵便番号っぽい文字列が含まれているか調べる if (System.Text.RegularExpressions.Regex.IsMatch( TextBox1.Text, @"\d\d\d-\d\d\d\d")) { Console.WriteLine("郵便番号が含まれています"); } //TextBox1内の郵便番号っぽい文字列をすべて抽出する System.Text.RegularExpressions.MatchCollection mc = System.Text.RegularExpressions.Regex.Matches( TextBox1.Text, @"\d\d\d-\d\d\d\d"); foreach (System.Text.RegularExpressions.Match m in mc) { Console.WriteLine(m.Value); } //TextBox1内の郵便番号っぽい文字列の"-"を削除して、【】で囲む TextBox1.Text = System.Text.RegularExpressions.Regex.Replace( TextBox1.Text, @"(\d\d\d)-(\d\d\d\d)", "【$1$2】");
以下によく使われるメタ文字とその意味を紹介します。詳しくはMSDNの「正規表現言語要素」をご覧ください。
文字 | 説明 | 使用例 |
---|---|---|
.(ピリオド) | 改行文字(\n)以外の任意の一文字。(ただし [] 内ではピリオド文字。) | 「.」 「」内に任意の1文字がある箇所にマッチ |
\s | 空白文字。改行文字、タブ文字、半角/全角スペース文字など。[\f\n\r\t\v\x85\p{Z}]と同じ。 (ちなみに \S は \s 以外の文字を表す。) | Visual\sBasic Visual と Basic の間に空白文字が1文字ある箇所にマッチ |
\d | 0から9までの数字。全角を含む。\p{Nd}と同じ。 (ちなみに \D は \d 以外の文字を表す。) | VB\d VB の後に数字が1文字ある箇所にマッチ |
\w | 単語に使用される文字。アルファベット、数字、アンダーバー(_)、ひらがな、カタカナ、漢字など。[\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}\p{Pc}\p{Lm}]と同じ。 (ちなみに \W は \w 以外の文字を表す。) | 「\w」 「」内に単語に使用される文字が1文字がある箇所にマッチ |
\r | キャリッジリターン。\u000Dと同じ。 | \r\n Windows の改行文字(CRLF)にマッチ |
\n | ラインフィード(改行文字)。\u000Aと同じ。 | \r\n Windows の改行文字(CRLF)にマッチ |
\t | タブ。\u0009と同じ。 | \n\t 改行文字(\n)の後にタブが続く箇所にマッチ |
\\ | 文字の前に \ を付けると、その文字。メタ文字の機能を無効にするときに使う。(ある文字列内のメタ文字をすべて \ でエスケープするには、Regex.Escapeメソッドを使うとよい。) | DOBON\.NET DOBON.NET にマッチ |
[ ] | []内のどれか1文字。[abc]ならば、aかbかc。 | VB[2456] VB の後に2か4か5か6が続く箇所にマッチ |
[^ ] | [^]内の文字以外の1文字。[^abc]ならば、aかbかc以外の文字。 | 「[^「」]」 「」内に「」以外の1文字がある箇所にマッチ |
[ - ] | 連続した文字範囲の1文字。[0-9]ならば、数字1文字。[a-zA-Z]ならば、アルファベット1文字。 | VB[24-6] VB の後に 2か4か5か6 が続く箇所にマッチ |
\u0000 | 4桁の16進数で表されるUnicode文字。 | [\uFF61-\uFF9F] 半角カナ文字の1文字にマッチ(詳細) |
\x00 | 2桁の16進数で表されるASCII文字。 | [\x20-\x7F] 半角英数記号文字(0x20~0x7F)の1文字にマッチ |
ここで紹介するメタ文字は、文字列内の位置を表現したものです。文字とマッチするわけではありません。
文字 | 説明 | 使用例 |
---|---|---|
^ | 文字列の先頭。 | ^\d 先頭にある数字1文字にマッチ |
$ | 文字列の末尾。ただし、文字列の末尾が \n の時は、その前と一致。(末尾が \n でも末尾で一致させるには、\z を使う。) | \d$ 末尾にある数字1文字にマッチ |
\b | 単語の境界(\w と \W の間)と一致。(ただし [] 内ではバックスペース文字。) (ちなみに \B は \b 以外の境界を表す。) | \bVB\b VB が単語として現れる箇所にマッチ |
ここで紹介する量指定子は、文字(または、グループ)の繰り返しを表現するものです。最長マッチと最短マッチの違いは非常に重要ですが、これについては後述します。
文字 | 説明 | 使用例 |
---|---|---|
* | 直前の文字が0回以上繰り返す。 | <[^>]*> <>で囲まれた箇所にマッチ |
+ | 直前の文字が1回以上繰り返す。 | <[^>]+> <>内に1文字以上ある箇所にマッチ |
? | 直前の文字が0回または1回繰り返す。 | -?\d+ マイナスが付いた数字、あるいは付かない数字にマッチ |
{n,m} | 直前の文字がn回以上m回以下繰り返す。 | \d{2,6} 数字が2文字以上6文字以下続いている箇所にマッチ |
{n} | 直前の文字がn回繰り返す。 | \d{6} 数字が6文字続いている箇所にマッチ |
{n,} | 直前の文字がn回以上繰り返す。 | \d{8,} 数字が8文字以上続いている箇所にマッチ |
*? | 最短マッチで、0回以上の繰り返し。? は *、+、?、{} の後につけて最短マッチを表すことができる。最短マッチと最長マッチについては、後述。 | <.*?> <>で囲まれた箇所にマッチ |
ここで紹介するグループ化を使用する主なケースとしては、論理和による選択を行う場合や、前方参照(後述)やMatch.Groupsプロパティでの抽出を行いたい場合などが挙げられます。
.NET Frameworkにはグループに名前(あるいは番号)を付けることができるという特徴があります。グループに名前を付けても付けなくても、グループには1から連番で番号が付けられます(番号0はパターン全体です)。
ここでは先読み、後読みアサーションも紹介していますが、これらは少し高度です。ですので初心者の方はこれらを無視していただいても構いませんが、知っておくとかなり役に立ちます。
ちなみに、後読みアサーションのパターンとマッチする文字列は固定長でなければならないとするエンジンが多いですが、.NET Frameworkではこのような制限がありません。
文字 | 説明 | 使用例 |
---|---|---|
| | | で区切られた文字列のいずれか(論理和)。 | リンゴ|りんご|林檎 リンゴ または りんご または 林檎 にマッチ |
( ) | グループ化する箇所。 | 山田(太郎|花子) 山田太郎 または 山田花子 にマッチ |
(?<name> ) | グループに名前(あるいは番号)を付ける。(ちなみに、< > の代わりに ' で括ることもできる。) | VB(?<ver>\d) VB の後に数字がある箇所にマッチし、数字を"ver"というグループ名でキャプチャ |
(?: ) | キャプチャしないグループ。 | 山田(?:太郎|花子) 山田太郎 または 山田花子 にマッチするが、太郎 または 花子 をキャプチャしない |
(?= ) | 直後にこのパターンが現れることを確認する(ゼロ幅の肯定的先読みアサーション)。 | \d+(?=%) 後ろに % が続く数字の連続にマッチ。ただし、% はマッチした箇所に含まれないし、グループとしてキャプチャもされない。 |
(?! ) | 直後にこのパターンが現れないことを確認する(ゼロ幅の否定的先読みアサーション)。 | \d+(?!%) 後ろに % が来ない数字の連続にマッチ。 |
(?<= ) | 直前にこのパターンが現れることを確認する(ゼロ幅の肯定的後読みアサーション)。 | (?<=\\)\d+ \ に続く数字の連続にマッチ。ただし、\ はマッチした箇所に含まれないし、グループとしてキャプチャもされない。 |
(?<! ) | 直前にこのパターンが現れないことを確認する(ゼロ幅の否定的後読みアサーション)。 | (?<!\\)\d+ 前に \ がない数字の連続にマッチ。 |
グループ化してキャプチャした文字列を後から参照することができます。これが前方参照(後方参照)です。これによって、キャプチャした文字列をパターンに埋め込むようなことができます。
文字 | 説明 | 使用例 |
---|---|---|
\number | 番号がnumberのグループと一致した文字列。 | <(H\d)>.*?</\1> <H>タグで囲まれた箇所にマッチ |
\k<name> | 名前がnameのグループと一致した文字列。(ちなみに、< > の代わりに ' で括ることもできる。) | <(?<tag>H\d)>.*?</\k<tag>> <H>タグで囲まれた箇所にマッチ |
前方参照(後方参照)と同じように置換パターン内で以下のような特殊文字を使用することができます。
前方参照と似ているため、使用例は省略します。使用例は、「正規表現を使って文字列を置換する」をご覧ください。
文字 | 説明 |
---|---|
$number | 番号が number のグループと一致した文字列。 |
${name} | 名前が name のグループと一致した文字列。 |
$& | パターン全体と一致した文字列。 |
オプションを指定することもできます。オプションを指定するとメタ文字の意味が多少変わるものもあります。.NETではオプションを指定するのにRegexOptions列挙体を使用します(インラインで使用する方法もありますが、ここでは紹介しません)。以下によく使われる重要なオプションを示します。
RegexOptions列挙体のメンバ | 説明 |
---|---|
IgnoreCase | 大文字と小文字を区別しない。 |
Singleline | .(ピリオド)の意味を変更し、\n を含めたすべての文字と一致するようにする。 |
Multiline | ^ と $ の意味を変更し、文字列全体の先頭と末尾だけでなく、行の先頭と末尾にも一致するようにする。具体的には、^ は \n の後、$ は \n の前(改行文字が \r\n であったとしても)にも一致するようになる。^ と $ の代わりに \A と \Z を使用すると、Multilineの影響を受けずに文字列全体の先頭と末尾に一致させることができる。 |
ECMAScript | ECMAScript準拠の動作とする。このことで、一部のメタ文字の意味が変更される。例えば、 \w は [a-zA-Z_0-9] と同じに、 \s は [ \f\n\r\t\v] と同じに、 \d は [0-9] と同じになる。その他詳しくは、「ECMAScript と標準一致の動作の比較」。 |
CultureInvariant | 言語の違いを無視する。 |
Compiled | 正規表現をコンパイルして実行速度を上げる。ただし、起動時間は長くなる。詳しくは、「コンパイルと再利用」。 |
最長マッチと最短マッチの違いは非常に重要ですので、ここで説明しておきます。
例えば、カギかっこ(「」)で囲まれた文字列を抽出するために次のようなパターン(コード)を書いたとします。
Dim mc As System.Text.RegularExpressions.MatchCollection = _ System.Text.RegularExpressions.Regex.Matches( _ TextBox1.Text, "「.*」")
System.Text.RegularExpressions.MatchCollection mc = System.Text.RegularExpressions.Regex.Matches( TextBox1.Text, @"「.*」");
このようなパターンでは、カギかっこが複数あった場合、問題が起こります。例えば、TextBox1に"・・・「あ」、「い」、「う」・・・"と入力されているならば、マッチする文字列は、"「あ」、「い」、「う」"の1つだけです。"「あ」"、"「い」"、"「う」"の3か所にマッチするようにするには、パターンを"「.*?」"と書き換えます。つまり、"*"の後ろに"?"を付けて、最短マッチにします。"?"を付けないと最長マッチになりますので、一致する箇所が最も長くなるような方法で検索が行われます。
ちなみに上記のような例であれば、最短マッチにしなくても、"「[^」]*」"と書けばほぼ同じことができます。
注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。