Match regexの使い方 - その1
日付 | 2008/08/22 |
---|---|
ID | 08-023 |
バージョン | 11 |
プラットフォーム | Mac & Win |
Match regexは、4D v11 SQLで採用されているICU(International Components for Unicode)が有するUnicodeに特化された正規表現を利用して文字列のパターンをマッチングするためのコマンドです。ちなみにPosition関数も内部的に同じルーチンを利用しています(アスタリスクを渡さなかった場合)。ICUの正規表現は、基本的に他の言語(Perl)などのそれと同じですが、Unicodeのテキストを評価する目的に特化されており、Unicodeではない文章やバイナリデータのサーチはできません。一方、Unicode特有の属性(プロパティ)に関連する正規表現が使用できるようになっています。
http://icu-project.org/userguide/regexp.html
もっとも基本的なMatch regexの使い方は、Position関数のそれとほとんど変わりません。つまり、テキスト内である文字列が出現する箇所を特定します。つまり次のコードはどちらも同じことをしています。
$Match_b:=Match regex("う";"あいうえお";1;$Position_l;$Length_l) $Position_l:=Position("う";"あいうえお";1;$Length_l)
上記の例で"う"の長さが分かっているのにも関わらずLength_lを調べているのには理由があります。Unicodeでは、等価とみなされる文字をいろいろな仕方で表現でき、中には長さ(コードポイント数)が異なるものもあるからです。たとえば、"パターン"というファイル名で文書を保存したとします。Mac OS Xの場合、ファイルシステムのルールにより「パ」という一文字は「ハ」と半濁音に分離されます。つまり等価とみなされる文字でありながら、一方はLengthが1、他方はLengthが2になります。Match regexで合致したパターンを抽出するためには、その長さも正確に調べる必要があるのです。
http://unicode.org/reports/tr15/
Substring関数は、文字列をその長さ(コードポイント数)で切り出します。つまり、PositionやMatch regexで受け取った値をそのまま渡すことができます。たとえば次のようにパターンに合致した文字列を取り出すことができます。ここで$Length_lの代わりにLength("う")のような書き方をしていると、前述のような複数のコードポイントで構成される文字(「う」と濁点の組み合わせなど)が含まれていた場合に問題が生じます。
$Result_t:=Substring("あいうえお"; Position_l; Length_l)
Positionと同様、Match regexにはパターンを構成する文字をそのまま渡すことができます。ただし、Positionとは違い、次の文字はバックスラッシュ記号でエスケープしなくてはなりません。* ? + [ ( ) { } ^ $ | \ . /
Match regexの強みは、実際の文字(リテラル)だけではなく、豊富なメタキャラクターやオペレータでパターンを構成できることにあります。メタキャラクターはリテラルな文字の代わりに置かれるものです。オペレータはリテラルな文字またはメタキャラクターの後に置かれ、特定の条件を付与します。多くの場合、最初に覚えるのは次のメタキャラクターとオペレータです。
メタキャラクター
オペレータ
たとえば、次のパターンでは、空白を無視したい位置には\\s*を置き、データを読みたい箇所には.+を置いているので、空白の有無に関係なく、データがあればパターンにマッチします。
$Match_b:=Match regex("\\s*content-length\\s*:\\s*.+\\s*";" content-length : 123 ";1;$Position_l;$Length_l)
ほとんどの場合、Match regexは、全体のパターンを評価するよりも、その中で特定のパターンにマッチする部分を取り出すために使用されます。つまり、上記の例では、全体として"content-length : ###"という形になっていることを調べるのが最終目的ではなく、###の値を調べること興味があるという意味です。Match regexで文字列の中から特定のパターンにマッチする部分を取り出すには、キャププチャリング括弧と位置/長さの配列を使用します。
はじめに、正規表現のパターンをいくつかのブロックに分解し、それぞれを括弧で括ります。
"(\\s*)content-length(\\s*):(\\s*)(.+)(\\s*)"
上記の例では、全部で5個のブロックに分解されており、4番目のブロック(.+)には、"content-length : ###"の###の部分が入ります。
ARRAY LONGINT(Position_al;0) ARRAY LONGINT(Length_al;0) $Match_b:=Match regex("(\\s*)content-length(\\s*):(\\s*)(.+)(\\s*)";" content-length : 123 ";1;$Position_al;$Length_al)
倍長整数の配列を宣言し、Match regexにパラメータとして渡すと、ブロックの数だけ要素を持つ配列のペアが返されます。それぞれの要素は各ブロックの開始位置と長さ(コードポイント数)に対応しています。"content-length : ###"の###の部分が入るのは4番目のブロック(.+)なので、###の値を取り出すのは次のようにSubstring関数を呼び出します。(もちろん、実践ではリテラルな文字列ではなく、テキスト型の変数に対してコマンドを実行します。)
$Value_t:=Substring(" content-length : 123 "; Position_al{4}; Length_al{4})