正規表現は高度なテキスト検索を行うための仕組みだと述べた。テキスト・エディタなどであれば確かにその通りなのだが、プログラミングに利用する場合はそれだけでなく、もう少し応用範囲が広い。文字列の検索を行うという点では変わらないが、その結果には幾通りかの使い方がある。
(1) 文字列がパターンに一致するか検証する
(2) パターンに一致する部分文字列を抜き出す
(3) パターンに一致する部分文字列を置換する
■文字列パターンの検証
(1)の用例としては、フォームに入力されたメール・アドレスが正しい書式であるか検証する、などが挙げられる。高い柔軟性を備えるとはいえ、文字列の比較でしかない正規表現によるチェックだけでは、そのメール・アドレスで正しくメールを届けられるかどうかまでは判断できないが、「<ユーザー名>@<ドメイン名>」のフォーマットにのっとっているかどうかをチェックするだけでも、不配メールをかなり減らせるはずだ。それに、悪意あるユーザーによってスクリプトが仕込まれるのを防ぐ目的でも、この種のチェックは有用だ。
■文字列のキャプチャ
こうした文字列パターンの検証に正規表現はうってつけだし、テキスト・エディタを使った日常的な作業の中では、これこそが正規表現の使いどころであるわけだが、実際のプログラミングでは、マッチするか否かの判定に使うよりも、むしろ(2)の部分文字列の抜き出し(キャプチャ)のために使うことが多く、また効果的だ。カンマで区切られたデータの羅列を分解したり、日付データを年月日に分解したり、あるパターンに一致する文字列を発見し、さらにその文字列からパーツを抜き出すような処理は、正規表現を活用すればお手の物だ。一般的にテキスト・データのパース(解析)は、データ・フォーマットの許容範囲が広いほど複雑なプログラムになりがちだが、正規表現をうまく使えば、非常にシンプルなプログラムで処理できることが多い。
■文字列の置換
(2)の応用となるが、パターンに一致した部分文字列を指定したルールで置換することも可能だ。例えば、パターンに一致した英字をすべて小文字に変換するなどの処理を簡単に記述できる。
3通りの活用法について述べたが、いずれにしろ、まずは目的の文字列にうまくマッチするパターンを組み上げなければ始まらない。そのために、これからメタ文字について解説していくのだが、その前に1つサンプル・プログラムを示しておこう(リスト1)。このプログラム「regex」は、コマンドラインで指定されたファイルの各行に<正規表現パターン>を適用し、マッチする文字列が含まれている行だけを表示するというものだ。ごく単純なgrepコマンド(主にUNIXやLinuxで使用される標準的なコマンド)だと考えてもらっていい。
このプログラムは、コマンド・プロンプトで次のようにして実行する。
regex <正規表現パターン> <ファイル名>
このプログラムを使って、これから解説する正規表現を実際に試してみることができる。なお、<正規表現パターン>で使用するメタ文字の中には、コマンドラインで特別な意味を持つ記号も含まれているので、この部分は以下のようにダブルクオートで囲んで指定した方がよい。
例: regex "^\s*//" regex.cs
using System;
using System.Text.RegularExpressions;
using System.IO;
class Grep {
/// <summary>
/// アプリケーションのメイン エントリ ポイントです。
/// </summary>
[STAThread]
static void Main(string[] args) {
TextReader reader = null;
try {
if (args.Length < 1) {
Console.Write("regex <正規表現> [<ファイル>]\n");
} else if (args.Length == 1) {
// ファイル名が指定されなかったときは標準入力から
reader = Console.In;
} else {
reader = new StreamReader(
args[1], System.Text.Encoding.GetEncoding(932));
}
if (reader != null) {
// 正規表現はRegexインスタンスに対して固定
Regex regex = new Regex(args[0]);
string line;
while ((line = reader.ReadLine()) != null) {
Match m = regex.Match(line); // lineから検索
if (m.Success) { // 一致すればtrue
Console.WriteLine(line);
}
}
reader.Close();
}
}
catch (Exception e) {
System.Console.WriteLine(e.Message);
}
}
}
このプログラムは、.NET Frameworkの正規表現クラスを扱った簡単なサンプル・プログラムでもある。そこで、正規表現を扱う肝の部分について先に解説しておこう。
.NET Frameworkの正規表現クラスは、すべてSystem.Text.RegularExpression名前空間にまとめられている。ここで宣言されているクラスのうち、中心的役割を担うクラスがRegexクラスとMatchクラスである。Regexクラスは正規表現パターンを格納し、パターン・マッチングを実行するメソッドを備えたクラス。MatchクラスはRegexクラスで実行されたパターン・マッチングの結果を格納するクラスである。
この2つのクラスを使って、正規表現によるマッチングを行う手順は以下のようになる。
これらをC#のコードで表現すると次のようになる。
Regex regex = new Regex(<正規表現パターンを含む文字列>);
Match m = regex.Match(<被検索文字列>);
if (m.Success) {
// パターンにマッチする文字列が1つ以上含まれていた場合の処理
}
Regexクラスのコンストラクタに正規表現パターンを渡すと、インスタンスの生成と同時に、正規表現のコンパイルが行われる。コンパイルといってもアセンブリへのコンパイルを意味するわけではなく、与えられた正規表現を解釈して内部で扱いやすい形式に変換する作業を意味している(本当にアセンブリへとコンパイルすることも可能だが通常は不要)。この作業が行われるため、一度生成されたRegexインスタンスの正規表現パターンが変更されることはない。
こうして生成されたRegexインスタンスからMatchメソッドを呼び出すと、与えられた<被検索文字列>の先頭からパターンに一致する文字列が検索され、結果を格納したMatchインスタンスが戻される。Matchクラスにはパターンに一致した部分文字列を表すプロパティなどのメンバが用意されているが、検索の可否を判断するだけならば、Successプロパティを参照するだけで済む。Successプロパティの値がtrueならば1つ以上の一致文字列が見付かったことを意味する。
Copyright© Digital Advantage Corp. All Rights Reserved.