先に示したリスト1のパースのためのコードは、以下に説明する正規表現を用いることで、区切り記号で区切られたファイルをパースするのにも使える。まずは、次のように、クォートされた文字列がファイルに存在しないという単純化した例で考えていこう。
John , Smith, New York Ann, Doe, Los Angeles |
気づいたかもしれないが、この例では、余分な空白を入れてある。テキストをパースする場合、これらの空白は無視されるべきだ。
カンマ区切りの一連の値をパースし、それと同時に、これらの余分な空白を無視するには、次の正規表現を利用できる。
^\s*(?<first>.*)\s*,\s*(?<last>.*)\s*,\s*(?<city>.*)\s*$ |
「\s*」というシーケンスは、「0以上の余白」を意味する。ここで言う余白とは、「空白(スペース)」「タブ」、そして「改行記号」だ。
これらの「\s*」シーケンスや「区切り文字(この場合はカンマ)」は、「(? )」の構成要素の外に置かれることが必要だ。そうすることで、指定されたグループに含まれなくなる。
さらに、フィールドが空であるときには、区切り記号が連続することもありうるため、「.*」シーケンス(これは0以上の文字を表す)を使っている点に注目してほしい。
では次に、以下のテキストファイルのように、クォートされたフィールドをパースする方法を見ていこう。
'John, P.' , "Smith" , "New York" 'Robert "Slim"', "" , "Los Angeles, CA" |
テキストフィールドは、シングルフォートとダブルクォートのどちらでも囲むことができる。そして囲まれている部分には、カンマやクォートの文字を含むことができ、それらは区切り記号としては働かない。
そのような行をパースできる正規表現は少し複雑だ。そこで便宜的に分割して考えていこう。
^\s*(?<q1>("|'))(?<first>.*)\k<q1>\s*, \s*(?<q2>("|'))(?<last>.*)\k<q2>\s*, \s*(?<q3>("|'))(?<city>.*)\k<q3>\s*$ (上記の行は、実際には1行で構成する) |
「(?<q1>("|'))」という部分式は、シングルクォートかダブルクォートという主要な区切り記号のいずれかと一致し、このグループに名前「q1」を割り当てる。
「\k<q1>」という部分式は、q1グループが見つけたものすべてへの後方参照だ。すなわち、「\k<q1>」は、フィールドの始めに使われた区切り記号(この場合、シングルクォートかダブルクォートのいずれか)に合致する。q2とq3は、次の2つのフィールドについて同じ役割を担っている。
繰り返すようだが、パースのルーチンのほかのステートメントを変更する必要はない。
ところで、.NET Framework 2.0の開発者は、System.Text.Parsing名前空間に用意されたTextFieldParserという真新しいクラスを使うことで、固定長や区切り記号で区切られたフィールドをパースすることもできる。
名前空間が示唆するものと違い、このクラスは、Microsoft.VislauBasic.Dllライブラリで定義されている。
したがって、C#アプリケーションは、このDLLへの参照を加えない限り、アクセスできない(何人かのC#プログラマーが、そうするのではないかと、筆者は恐れている)。
私は、TextFieldParserクラスと同等の機能をもつクラスを用意した。このクラスは、.NET2TheMaxサイトからダウンロードできる(コラム「Additional 2TheMax Downloads」参照)。――Francesco Balena
|
© Copyright 2001-2005 Fawcette Technical Publications