4.5. パターンマッチング

Postgresでは、SQLLIKE演算とPOSIX形式の表現、 2種類の方法でパターンマッチングを行えます。

Tip: これらのパターンマッチング機能以上のものを必要とされる場合や、 パターンの置換、変換などはPerlやTclのユーザ定義関数を作成してみて下さい。

4.5.1. LIKE述語を使用したパターンマッチング

string LIKE pattern 
[ ESCAPE escape-character ]
string NOT LIKE pattern 
[ ESCAPE escape-character ]

すべてのpatternでは文字列の定義を行います。 LIKE述語では、stringpatternの中に含まれているならばtrue(真)を 返します。(ご察しの通り、LIKE述語でtrue(真)が 返るならば、NOT LIKE述語ではfalse(偽)となります。 NOT (string LIKE pattern)も同じ動作をします。)

patternにパーセント記号やアンダースコアが含まれて いないならば、そのpatternは文字列そのものを 意味します。この場合、LIKEはイコール演算子のような 働きを行います。patternの アンダースコア(_)はあらゆる1文字を意味し、 パーセント記号(%)は0文字以上の文字を意味します。

例:

'abc' LIKE 'abc'    true
'abc' LIKE 'a%'     true
'abc' LIKE '_b_'    true
'abc' LIKE 'c'      false

LIKEでは、パターンマッチは文字列の最初から最後まですべて で行われます。したがって、文字列のある部分に対してパターンマッチを 行いたい場合は、パターンの最初と最後にパーセント記号を付ける必要があります。

アンダースコアやパーセント記号そのものをパターンマッチさせたい場合は patternの文字1字づつエスケープ文字で 指定する必要があります。ディフォルトのエスケープ文字はバックスラッシュ ですが、ESCAPE句を使用することによって 変更が可能です。エスケープ文字そのものとのマッチさせたい場合は、 エスケープ文字を2つ記述して下さい。

文字列において、バックスラッシュが特別な意味をすでに持っていることに ご注意下さい。したがって、パターンの定数にバックスラッシュが含まれる ものを記述する際には、問い合わせに必ずバックスラッシュを2つ記述して下さい。 これを回避するにはESCAPEで別のエスケープ文字を選択して下さい。

アクティブロケールよるマッチを行う際には、LIKEではなく、 ILIKEを使用することも可能です。 これは標準SQLではなく、Postgres 独自の拡張です。

~~演算子はLIKEと同様で、 ~~*ILIKEと対応しています。 また、NOT LIKEには!~~NOT ILIKEには!~~*の演算子が 割り当てられています。これらもPostgres 特有のものです。

4.5.2. POSIX正規表現

Table 4-8. 正規表現演算子

演算子説明
~ 大文字/小文字の識別を含んで、一致するかを識別 'thomas' ~ '.*thomas.*'
~* 大文字/小文字の識別をしないで、一致するかを識別 'thomas' ~* '.*Thomas.*'
!~ 大文字/小文字の識別を含んで、一致しないかを識別 'thomas' !~ '.*Thomas.*'
!~* 大文字/小文字の識別をしないで、一致しないかを識別 'thomas' !~* '.*vadim.*'

POSIXのパターンマッチングはLIKE述語よりも 強力なものです。egrepsedawkなどの多くのUnixツールはここで説明されているものと 同じような正規表現言語を使用しています。

正規表現は文字のシーケンスで、複数の文字列(regular set) の短縮された定義です。正規表現で説明されているregular set が文字列と一致する場合、正規表現と一致する、と言われます。 LIKEでは、正規表現言語で特別な意味を持つ 文字を除いて、文字列とパターン文字列は完全に一致するかを検証します。 しかし、正規表現ではLIKE述語が使用する特別文字とは 異るものを使用します。LIKE述語のパターンとは 違って、「文字列の頭から」や「後から」などの指定がない限り 正規表現は文字列のどの部分でもマッチできます。

正規表現("RE"s)は2つのフォームがあると POSIX1003.2で定義されています。1つは モダンREs(modern REs)、(egrepなどで、1003.2では "extended" REsと呼ばれています。)あと1つは旧式REs (obsolete REs;ed;1003.2 "basic" REs) です。

モダンREsは1以上の空ではないブランチで、 |で区切ってあります。このブランチの1つでも 一致するものがあれば一致します。

ブランチとは、1以上のピースが 連なっているものです。1番目にマッチしたら、2番目、といった感じで マッチさせていきます。

ピースとはアトムで、大方、1つの*+?boundが 続きます。*が後にあるアトムは0以上のアトム と一致します。+が後にある アトムは1以上のアトムと一致します。 ?が後にあるアトムは0か1のアトムと一致します。

bound{の後に 符号無し10進数整数が続き、その後には通常は,があり、その後には 通常はまた符号無し10進数整数があり、必ず}が最後につきます。 この符号無し10進数整数は必ず0からRE_DUP_MAX(255も含む)までの 数字である必要があり、2つある場合は1つめは2つめよりも小さくなければなりません。 アトムには、その後に1つの整数i(カンマなし)を 持っているバウンド(bound)があるものがあり、そのアトムはアトムの 丁度i個のマッチしたシーケンスとマッチします。 アトムの後に1つの整数i(カンマあり)を 持っているバウンド(bound)があるアトムはi個以上の マッチしたシーケンスとマッチします。 アトムの後に2つの整数 ijがあるものは iからj(jも含む)の シーケンスのマッチしたシーケンスとマッチします。

Note: ?*+、 バウンドなどの反復演算子は他の反復演算子と併用することはできません。 反復演算子は式やサブ表現を開始したり、^、または |を追従することはできません。

アトムとは、正規表現が()で囲われているもの (正規表現のマッチに一致する)、空の() (NULL文字列と一致する)、bracket expression (下記参照)、.(あらゆる1文字と一致)、^ (入力された文字列の最初の文字がNULL文字列と一致)、$ (入力された文字列の最後の文字がNULL文字列と一致)、^.[$()|*+?{\ の直後に1つの\(普通の文字とされる文字と一致)、 \の直後にその他の文字(\が無視され、 普通の文字とされる文字と一致)、または他の特徴がない1文字(その文字と一致)です。 {の直後で、数字以外の文字は通常の文字で、バウンドの 最初ではありません。\でREを終了させるのは 禁じられています。

文字列において、バックスラッシュ(\)はすでに特別な 意味を持っていることにご注意下さい。したがって、パターンの定数に バックスラッシュが含まれるものを記述する際には、問い合わせに 必ずバックスラッシュを2つ記述して下さい。

ブラケット表現(bracket expression)とは、 文字のリストが[]で囲われたものです。通常リストにある どの文字にもマッチします(下記参照)。もしリストが ^ から始まるならば、どの文字にも一致しますが(下記参照)、それ以降のリスト とはマッチしません。2つの文字の間に-がある場合、 これはその文字と文字の間(その文字も含む)に存在する文字のシーケンス を意味します。例えば、[0-9]ASCII マッチではすべての10進数と一致します。また、2つの範囲(range)指定で、始点/終点 (エンドポイント)を共用することはできません。(例:a-c-e)。 範囲はシーケンスの照合にとても依存しているので、簡易プログラムでは 使用を避けて下さい。

]をリストに含めるには、それを最初の文字 (^があればその後)にして下さい。- を含めたい場合は、最初か最後、または範囲(range)の2番目のエンドポイントと して下さい。-を最初のエンドポイントとする場合は、 照合要素(collating element;下記参照)にするために -[..] で囲んで下さい。これらの例外と[(次の段落参照)の 組み合わせ方を除き、\も含むすべての特別な意味を 持つ文字はその効果をブラケット表現(bracket expression)内では 失います。

ブラケット表現(bracket expression)では、[..]で囲われた照合要素(1文字、または複数の文字のシーケンス で、1文字またはどちらかの照合シーケンス名)はその照合要素文字の シーケンスを意味します。シーケンスとはブラケット表現のリストの 1つの要素となります。したがってブラケット表現内にマルチバイト文字が ある場合は、1文字以上の文字と一致します。例えば、照合シーケンスに chという照合要素があった時、REの [[.ch.]]*cではchchccの 最初の5文字とマッチします。

ブラケット表現内で、[==]で 囲われた照合要素は同等クラス(equivalence class)で、それと等しい すべての照合要素の文字で構成されたシーケンス(それそのものも含む) を意味します。(等しい照合要素がない場合は、[.^はデリミターとして扱われます。)例えば、 o^が同等クラスの要素だった場合、 [[=o=]][[=^=]][o^]はすべて同義となります。同等クラスは範囲(range) のエンドポイントにはできません。

ブラケット表現内で、[::]で 囲われた文字クラス(character class)の名前は、そのクラスに属する すべての文字のリストを意味します。下記は標準な文字クラスの名前です: alnumalphablankcntrldigitgraphlowerprintpunctspaceupperxdigit。 これはctypeで定義されている文字クラスを 意味します。ロケールでは他のものも使用可能となる場合があります。 文字クラスは範囲(range)のエンドポイントにはできません。

ブラケット表現には[[:<:]][[:>:]]の 2つの特殊なケースがあります。両方とも単語の始めと終わりそれぞれ のNULL文字列にマッチします。単語とはその前後に別の単語文字(word characters)が 存在しない、単語文字(word characters)のシーケンスと定義されています。 単語文字(word characters)とは (ctypeで 定義されているアルナム(alnum)文字、またはアンダースコアのことです。 これは拡張で、POSIX 1003.2では明記されていませんが、互換性があります。 しかし、他のシステムなどに移植される予定のソフトウェアなどでは 注意が必要です。

REが1つ以上の指定部分文字列と一致した際、REでは最初に一致した 文字列とマッチします。その場所からまた1つ以上の指定部分文字列 と一致した際には最も長い文字列と一致します。サブ表現では、 すべてのマッチは可能な限り長いという制約を条件とし、 可能な限り長い指定部分文字列ともマッチし、その際、REでは最初の 指定部分文字列を後のものよりも優先させてマッチします。

マッチの長さは参照要素ではなく、文字(character)で測られます。 空文字列は全く一致するものがない文字列よりも長いとされます。 例えば、bb*abbbcの 真ん中の3文字と一致し、(wee|week)(knights|nights)weeknightsの10文字すべてと一致します。 しかし、(.*).*abcと 一致しないとき、括弧で囲われた指定部分文字列は3つすべての 文字と一致し、また、(a*)*bcと 一致しない場合はREのすべてと括弧で囲われた指定部分文字列はNULL文字と 一致します。

汎用正規表現が指定された場合、アルファベットから特定の場合が 取り除かれた時のようになります。複数の特定の場合に、ブラケット表現外で 通常の文字として扱われる文字がある時は、 x becomes [xX]のように、 両方の特定の場合を持ったブラケット表現に変換されます。

REにはメモリが足りているのであれば、特に長さ制限はありません。 メモリの使用はおおよそREのサイズの線形(linear)で、バウンド反復 (bounded repetition)以外はREの複雑さに関係がありません。 バウンド反復とはマクロ拡張で実装されていて、バウンド反復が 入れ子になっていたりカウントが大きければとても場所と時間を 取ってしまいます。例えば、 ((((a{1,100}){1,100}){1,100}){1,100}){1,100} は(結局は)存在するほとんどのマシンをスワップ領域から脱出させます。 [1]

Notes

[1]

これは1994年に書かれたものです。数値は変更している かも知れませんが、問題は存続しているでしょう。