― .NET Frameworkがサポートする正規表現クラスを徹底活用する ―:基礎解説 スマートな文字列処理のための 正規表現入門(前編)(3/4 ページ)
正規表現をうまく使いこなせば、数十行のコードにも匹敵するテキスト処理をたった数行で実現することも可能だ。今回はまず、正規表現の基礎について解説する。
メタ文字
それでは、.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文字にマッチする」という原則に反して、“¥<文字>”の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.