正規表現について(復習編)
正規表現(Regular Expression)ってIndesignにも実装されてますし、Javascriptにもgrep Objectなんてものがありますので、本当はばりばり活用するべきものなのだろうけど、ついつい面倒でさけて通れるならまわりみち〜なんてものぐさな怠け者です。
まあ、そういっても必要な時はやはり使わなければいけない訳です。しかし、そんなことやってると記憶の彼方で霞んでいるのが世の常。いや、そんな事言ってるUnix使いお前だけだよって言われそうですが。今回は反省の意味も込めてREの走り書きをまとめてみました。
メタキャラクタで検索
a
単純に「a」にマッチしちゃいます。
メタキャラクタ以外の文字は、その文字自身にマッチします。ではメタキャラって何ってなるんだけど、要するに何か特別な意味合いが込められた大切なキャラクタ達の事なんです。
という事で例を挙げてみよう。
.
非常に判りにくいです。ドット(ピリオド)なんですが、これは任意の1文字にマッチするREなんです。
*
次に*は、直前の文字の 0 文字以上の連続にマッチします。注意する所はWindowsでいうワイルドカードと混同しない様にってところですかね。
a*
という具合にするとaにもマッチしますが、aaaaaaaaaaaaaaaaaなんてのにもマッチしちゃいます。ここで注意しないといけない所があります。 0文字以上ってところです。Indesignで正規表現検索かけるとわかりますが、文字と文字の間も検索にかかります。
これは空文字列というものが引っかかっているからなんです。難儀なものです。
ですからこういう場合は
aa*
という具合にaに続く0文字以上のaの連続という風な一見特異な記述になっちゃいます。が、perl程度の実装を行っているREでは気のきいたメタキャラがあります。
a+
+というメタキャラは直前の文字1文字以上にマッチします。
では、ここで非常によく使われるメタキャラの組み合わせを
.*
頭から順に評価してみますと、任意の文字の0個以上の連続ってなりますので、おおよそ何でも引っ掛けちゃうREなんです。もちろん空文字もひっかかります。
.+
空文字はいやって場合はこちらです。
これら*や+の注意点ですが単体ではマッチしません。直前の1文字は必須ですのでご注意ください。
範囲とか限定してみる
しかしながら何にでもマッチするという表現を使うのは通常の場合限定的です。実際は数字だけとかアルファベット大文字だけとかを検索する場合が多い訳です。では、どうするかというと、
[0123456789]
上の例ではブラケットで囲まれた部分に数字が並べられています。こうすると「0か1か2か…8か9」にマッチします。任意の1文字からブラケット内の1文字と選択範囲がぐんと狭くなりました。
しかしながら無駄に長いです。この様な記述方法では、大文字アルファベットだけでも26文字書かないといけません。それを解消しましょう。
[A-Z]
大文字のアルファベットを引っ掛ける場合はこうするんですが、範囲指定ですね。何の範囲かと申しますと文字コード表です。このコード表というのはAsciiキャラクタ領域(要するに半角英数字ね)では互換性がありますが日本語に関しては環境によって若干の違いが生じます。
上記の見本はOSX10.6.4及びOS9.2.2における文字パレットのひらがなの部分ですが、UTFで拡張された文字のせいで少し違ってますね。漢字の領域なんて考えたくもないです。が、Indesignには漢字のメタキャラが実装されています。
~K
これで漢字一文字に該当します。話を戻して、
[ぁ-ゖ]+
上記の例はIndesignでひらがなの部分を引っ掛けるためのREです。以上の様に範囲を指定する場合はブラケット内でform toを-(ハイフン)でつなぐ感じですね。
これ以外でおなしゃす(^-^)/
範囲指定を否定する事も出来ます。
[^0-9]
違いはというと、頭のブラケットに続く^です。この位置に^がくると続くキャラクタ群の否定となります。要するに0-9以外、回りくどいですが数字以外という事になります。
注意としては^は必ず先頭に来ます。^の効力は先頭以外では発揮されません。
[0-9^]
上記の例では0-9及び^が引っかかります。^のご利益は先頭に置かれた時のみ発揮されると言う事ですから当然ですね。
さて、ブラケット内では幾つかのお約束があります。遅いですがここで書いておきましょう。
- メタキャラは基本的に効力を失い。該当するキャラクタが引っかかる。
- 「-」(ハイホン)は範囲を表す。「-」を検索対象に加えたい場合は先頭に記述。
- 「^」が先頭に来た場合は続くキャラクタ以外が検索対象となる。
- ブラケット「[]」を含めるたい場合、始まりの「[」はどこでも置けるが、閉じ側の「]」は先頭でないといけない。
- perlなどの実装ではバックスラッシュでエスケープするメタキャラクタはメタキャラクタの性質を失わない。
ブラケット内は基本打ち込んだままが評価されます。例外は範囲を現すための「-」や、後続を否定する「^」。これらのキャラクタは本来あるべき位置(「-」ならキャラクタの間、「^」なら先頭)を外れた位置に入力されると検索対象のキャラクタとして認識されます。
ブラケットですが始まりのほうは何処でも認識しますが、閉じ側は先頭にあると検索対象として認識します。後ろに存在する場合は問答無用でブラケットを閉じる事になります。
[a-c]def]
上記の例だとaまたはbまたはcで始まりdef]と続く文字列にヒットしちゃいます。まあ、こんなどんぐさい記述はしないとは思いますが。
最後のバックスラッシュ絡みのメタキャラはまだ出て来ていませんが、一応説明しておきましょう。
\n,\t,\r などなど…
javascript 使っているとたまに見ることがあると思いますが、ラインフィードやタブ、キャリッジリターンとか呼ばれる制御コード系のキャラクタの表現です。これ等はブラケット内に記述した場合でも「\」と「n」の様に分解して認識する事はありません。あくまでも改行コードとして認識します。もし文字列として認識させたい場合は頭のバックスラッシュをエスケープします。
[\\n]
これで「\」または「n」と解釈されます。
ではここでIPアドレスをマッチさせたい場合を考えてみましょう。
74.125.16.1
上記はググルせんせが最近はじめたサイトのサムネイルサービスのクローラのアドレスですが、4つの数字の塊が「.」で区切られていますね。
[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+
単純に数字が幾つか並んでドットで区切られての繰り返しで表現して見ました。しかしながらエレガントさに欠ける様な気もしますね。
IPアドレスは一つのデジットが0~255ですので
[12]?[0-9]+\.[12]?[0-9]+\.[12]?[0-9]+\.[12]?[0-9]+
うむむ…更にカオスな様相を呈してきましたねw
ここで「?」が出てますが、これは直前の文字が0もしくは1個ある?って疑問文だと思ってください。
さらに
[12]?\d{1,2}\.[12]?\d\{1,2}.[12]?\d{1,2}\.[12]?\d{1,2}
「\d」が出ました。edとかsedあたりの処理ではお目にかからない構文ですね。このあたりの[\]によるメタキャラはperlあたりからの実装です。もちろんIndesignでも使えますので一応解説しておきましょう。
\d
バックスラッシュが付いた「d」です。これは[0-9]に相当します。
\D
Dと大文字になると[^0-9]と等価です。要するに数字以外にまっちします。
さらに{}(ブレース)にはさまれた部分があります。これは直前の文字の連続の数を表してます。
a{2,4}
と言う具合だと、aが2~4個連続する文字列にマッチします。aaとかaaaとかaaaaにマッチすると言う事ですね。
このブレースにはさまれた数字の書き方で若干動作を変えられたりします。
a{2}
ずばりaが2個連続したaa
a{2,}
「,」が付いて後ろの引数が省略された形です。aの2個以上の連続と解釈します。
ここで前出の
[12]?\d{1,2}\.[12]?\d\{1,2}.[12]?\d{1,2}\.[12]?\d{1,2}
を頭から解釈してみましょう。1か2が頭にあるかもしれないけど無くてもいい数字1桁もしくは2桁に続いてドットがあって、次に1か2が続いてるかもしれない…これぐらいにしておきましょうか。
とどのつまり
\d+\.\d+\.\d+\.\d+
…もうこれでイイヨ。
意外に長くなってますのでこれぐらいで続きます。