それでは、.NET Frameworkの正規表現で利用できるメタ文字について解説していこう。これ以降の解説には、前述したregexコマンドと、そのソース・ファイルであるregex.csをサンプルに利用していく。
■通常文字
まず、regexのソース・コードからコメント行を検索するパターンを考えてみよう。C#のコメントは、「/* 〜 */」や「// 〜」など複数の書式で記述できるが、リスト1ではさいわい「// 〜」しか使われていないので、単純に「//」が含まれている行を検索すれば、コメント行を見つけることができる。文字列定数内で「//」を使用していると、コメント行ではない行もコメント行として見付かってしまうが、見落としはないのでここではよしとしたい。
regex "//" regex.cs
/// <summary>
/// アプリケーションのメイン エントリ ポイントです。
/// </summary>
// ファイル名が指定されなかったときは標準入力から
// 正規表現はRegexインスタンスに対して固定
Match m = regex.Match(line); // lineから検索
if (m.Success) { // 一致すればtrue
いま指定した「//」のように、パターンにメタ文字が一切含まれていなければ、指定された文字列そのものの検索が行われる。文字列内から指定した文字列のインデックスを取得するString.IndexOfメソッドと同様な検索が行われるということだ。メタ文字と組み合わせた場合でも、メタ文字でない文字は、そのものとだけマッチする。.NET Frameworkの正規表現では、以下の文字がメタ文字として扱われるので、これ以外の文字はごく普通の比較が行われる。
. | $ | ^ | { | } | [ | ] | ( | ) | | | * | + | ? | \ |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
.NET Frameworkで使用されるメタ文字 |
逆に、メタ文字として扱われる文字をそのものとして(通常の文字として)検索したければ、“¥”でエスケープしなければならない。例えば、「args[1]」という文字列を検索したいとしよう。このとき、以下のようにそのまま「args[1]」を指定すると、結果は何も表示されない。
regex "args[1]" regex.cs
後で解説するように、“[ 〜 ]”は「角括弧で囲まれたいずれか1文字に一致する」正規表現である。つまり、「args1」を検索したことになってしまうからだ。
正しく“args[1]”を見つけたければ、以下のように“[”と“]”を“¥”でエスケープしなければならない。
regex "args\[1\]" regex.cs
args[1], System.Text.Encoding.GetEncoding(932));
■[ 〜 ]
ちょうど話が出たので、“[ 〜 ]”について解説しよう。前述したように、この角括弧は「指定した文字のいずれか1文字にマッチする」正規表現である。例えば、以下のように“[=!]”を指定すると「=」か「!」にマッチするため、“[=!]=”で「==」か「!=」を含む行を検索できる。
regex "[=!]=" regex.cs
} else if (args.Length == 1) {
if (reader != null) {
while ((line = reader.ReadLine()) != null) {
この表現を利用すれば、“[0123456789]”として「任意の数字1文字」にマッチするパターンを表現できる。ただ、この調子で「任意のアルファベット」にマッチするパターンを表現しようとすれば、大文字小文字あわせて52文字もの文字を並べなければならなくなってしまう。そこで、1文字ずつ並べる代わりに、“[a-c]”のように文字の範囲を指定する書式も許されている。この書式を利用すれば「任意のアルファベットか数字1文字」にマッチするパターンを“[A-Za-z0-9]”のように簡潔に表現することができる(ハイフン自体をこれに含めたい場合には、角括弧内の先頭か末尾に“-”を記述すればよい)。
regex "[0-9]" regex.cs
if (args.Length < 1) {
} else if (args.Length == 1) {
args[1], System.Text.Encoding.GetEncoding(932));
Regex regex = new Regex(args[0]);
このように2通りの書式がある“[ 〜 ]”だが、このほかにも幾つか特殊なルールが決められている。
メタ文字そのものを検索したければ、“¥”でエスケープしなければならないのはすでに述べたとおりだが、角括弧の中ではメタ文字が特殊な意味を失い、その文字自身としか一致しない通常の文字として扱われる。つまり、“[$*+]”と書けば「$」か「*」か「+」にしか一致しないのである(いずれもメタ文字)。従って、基本的に角括弧の中では、メタ文字であろうがなかろうが、1文字がそのもの1文字にしか一致しない。
regex "[([][0-9]" regex.cs
args[1], System.Text.Encoding.GetEncoding(932));
Regex regex = new Regex(args[0]);
ただし、このルールにも例外がある。“¥”と“^”である。
“¥”はメタ文字をエスケープする働き以外にも、C#などのプログラミング言語と同じく、正規表現でもコントロール・キャラクタを表すために利用される。“\n”は改行文字(0x0a)と、“\t”はタブ文字(0x09)と一致するという具合だ。
regex "\t\t\t\t\t" regex.cs
args[1], System.Text.Encoding.GetEncoding(932));
Match m = regex.Match(line); // lineから検索
if (m.Success) { // 一致すればtrue
Console.WriteLine(line);
}
これらエスケープ・キャラクタは角括弧の中でも解釈されるため、「そのもの1文字にマッチする」という原則に反して、“¥<文字>”の2文字で1文字にマッチすることになる。このため、“¥”を角括弧に含めたい場合は、“¥¥”としなければならない。
regex "[\t\\][a-z]" regex.cs
static void Main(string[] args) {
try {
if (args.Length < 1) {
Console.Write("regex <RegularExpression> [<filesname>]\n");
reader = Console.In;
reader = new StreamReader(
args[1], System.Text.Encoding.GetEncoding(932));
if (reader != null) {
string line;
while ((line = reader.ReadLine()) != null) {
if (m.Success) { // 一致すればtrue
reader.Close();
catch (Exception e) {
もう1つの例外が“^”である。まだ解説していないが、正規表現において“^”は「文字列の先頭」を表すメタ文字である。通常メタ文字は文字に一致するパターンとして利用されるが、“^”は文字ではなく、「先頭」という位置にマッチするという点で少々特殊なメタ文字である。なお、反対に「文字列の末尾」に一致するメタ文字として“$”が用意されている。
ただし“^”が角括弧の中で、かつ“[”の直後で使われた場合には特別な意味を持つ。こうすると、角括弧の意味が「指定した文字に含まれていない任意の一文字」に変化する。例えば、“[^A-Za-z0-9]”とすれば、英数字以外の1文字にマッチするパターンとなる。“[ 〜 ]”の意味が逆転するわけだ。
regex "^[^\t]" regex.cs
using System;
using System.Text.RegularExpressions;
using System.IO;
class Grep {
}
なお、先頭以外で“^”が指定された場合は、ほかのメタ文字と同じく普通に“^”にだけマッチする文字として扱われる。
更新履歴
【2003/04/15】 “[ 〜 ]”内でのハイフンの取り扱いについて追記しました。
Copyright© Digital Advantage Corp. All Rights Reserved.