^(?<first>.{6})(?<last>.{8})(?<city>.+)$
「ドット(.)」は、「任意の文字」表す。すなわち、「.{6}」は、「任意の6文字」である。
「(?<first>.{6})」という式は、最初の6文字と一致する「first」という名前のグループを作る。同様に「(?<last>.{8})」という式は、次の8文字と一致する「last」という名前のグループを作る。最後の「(?<city>.+)」という式は、残った行末部分までの文字をグループ化した「city」という名前のグループを作る。「^」と「$」という文字は、それぞれ、「行頭」と「行末」だ。
ファイルをパースするには、VBやC#を使って、この正規表現を使った短いルーチンを書ける(リスト1は、ここからダウンロードできる)。
下記のVB.NETおよびC#のコードは、正規表現を使って固定長のテキストファイルをどのようにパースするかを示した断片的なものだ。カンマ区切りテキストファイル(ダブルクォーテーションによってクォートされたものも含む)をパースするには、正規表現のパターン部分を編集すれば良く、その他のステートメントを変更する必要はない。
' VB.NET
Dim sr As New StreamReader("c:\data.txt")
Dim pattern As String = _
"^(?<first>.{6})(?<last>.{8})(?<city>.+)$"
Dim re As New Regex(pattern)
Do While sr.Peek <> -1
Dim ma As Match = re.Match(sr.ReadLine())
Console.Write("First name = " & _
ma.Groups("first").Value.TrimEnd())
Console.Write(", Last name = " & _
ma.Groups("last").Value.TrimEnd())
Console.WriteLine(", City= " & _
ma.Groups("city").Value.TrimEnd())
Loop
sr.Close()
// C#
StreamReader sr = new
StreamReader("c:\\data.txt");
string pattern =
@"^(?<first>.{6})(?<last>.{8})(?<city>.+)$";
Regex re = new Regex(pattern);
while ( sr.Peek != -1 )
{
Match ma = re.Match(sr.ReadLine());
Console.Write("First name = " +
ma.Groups["first"].Value.TrimEnd());
Console.Write(", Last name = " +
ma.Groups["last"].Value.TrimEnd());
Console.WriteLine(", City= " +
ma.Groups["city"].Value.TrimEnd());
}
sr.Close();
正規表現に基づいたこのアプローチの美しいところは、フィールド長や区切り記号(デリミタ)が変わっても、それに対応させるのが信じられないほど容易という点だ。
例えば、固定長フィールドがセミコロンで区切られる場合、コードを変更することなく、次のように正規表現を修正すればよい。
^(?<first>.{6});(?<last>.{8});(?<city>.+)$
いちど正規表現の動きを理解してしまえば、パーサールーチンの作成や修正は、まるで子供の遊びのように簡単になってしまうだろう。――Francesco Balena
さて、ほかのアプリケーションとのデータ交換に主として使われている「区切り記号で区切られたテキストファイル」をパースするプログラムを書きたいとしよう。
フィールドは、それぞれ、「カンマ」「セミコロン」「タブ」や、その他の特殊記号によって分割される。さらに自体が複雑なのは、そのようなファイルには、シングルクォート(')やダブルクォート(")が値に含まれることを許すという点だ。
この時、パースするためにStringクラスのSplitメソッドを使うことはできない。なぜなら、クォートされた値が、「"Doe,John"」のように、区切り記号を含んでいるならば、正しい結果とならないからだ。
正規表現は、まさにそのような時の救い主だ。
© Copyright 2001-2005 Fawcette Technical Publications