一般的な正規表現を使ったツールでは中級編までの内容がそのまま使えると思います。 たとえばSedやAWKならば問題なく使えます。
ここではPerl等のかなり強力なツールでしか使えないような表現を説明します。
もちろん、K2Editorでも使える表現です。
中級編でも繰り返し表現が出てきました。Perlには拡張した繰り返し表現があります。
以前出てきた繰り返し表現では、繰り返し回数を指定する事はできませんでした。
たとえば、aの3回繰り返しを検索したい場合、 「a+」では3回繰り返し以外でもマッチしてしまいます。 ですから、「aaa」としなければなりません。
拡張された表現では繰り返し回数を指定できます。
基本的な書式は「{n,m}」です。 nが最小回数、mが最大回数です。 最大と最小が同じ場合、つまり固定回数の時には 「{n}」と書きます。
aの3回繰り返しは 「a{3}」と書けます。
2回以上5回以下の繰り返しは 「{2,5}」と書けます。
5回以上の繰り返しは 「{5,}」と、最大回数を省略する事で可能です。
では、4回以下の繰り返しは 「{,4}」となるでしょうか?
これは認識してくれません。「{0,4}」としてあげます。 必ず1つは存在しなければならないのであれば「{1,4}」です。
最大値は省略できますが、最小値は出来ないと思ってください。 だから固定回数の時も‘{m}’ではなく、‘{n}’と表現されているのでしょう。
一応文献をあたって、妥当と思われる表現を選んで記述しています。 繰り返しの場合、‘{m}’と書いている文献は見当たりませんでした。
正規表現中のある位置にマッチした文字列を後から使いまわす事が出来るのが後方参照です。
よく目にするのは置換する時でしょう。
グループ化した正規表現にマッチした部分文字列は正規表現内でキャッシュされます。
たとえば置換をする時、検索語を「(\w+)Editor」、 置換語を「$1Soft」とすると、 ‘Editor’の部分を‘Soft’に置き換えた文字列になります。 ‘K2Editor’に対して行えば‘K2Soft’になるわけです。
これが後方参照の基本的な形になります。
後方参照を行うには後から参照したい部分パターンをグループ化しておきます。 そして、使う時にそのグループの出現位置を指定する事でそこにマッチした文字列を参照します。
たとえば、
FORMULA-1:3000 FORMULA-3:2000
という文字列に対して 「([\w\-]+):(\d+)」で検索すると、 「$1」には ‘FORMULA-1’,‘FORMULA-3’といった文字列が、 「$2」には ‘3000’,‘2000’といった文字列が、入ってきます。
このように、‘$X’のいう表現は、前から数えて何番目のグループかを表しています。
後方参照は検索文字内で使う事も出来ます。この場合、‘\X’という表現になります。
IndyCar=3500:WRCar=2000
という文字列に対して 「(\w{4})(\w{3})=\d+:\w+\2」で検索すると、 IndyCar=3500:WRCarまでがマッチします。
これは最初のグループ「(\w{4})」に ‘Indy’がマッチし、 これが\1($1でもある)となり、次のグループ 「(\w{3})」に ‘Car’がマッチして、 これが\2となり、 「\w+」に ‘WR’がマッチした後、 \2を参照して、 ‘Car’までがマッチする訳です。
IndyCar=3500:MotoGP=990
だとマッチしません。 これは\2にあたる ‘Car’が存在しないからです。
このように、後方参照は『文字列』を参照するのであって、 『正規表現』を参照する物ではない事に注意して下さい。
上記の例で「((\w+)=(\d+):(\w+)=(\d+))」を検索した場合、 $Xにはなにが入るか分かりますか?
| $1 | IndyCar=3500:MotoGP=990 |
|---|---|
| $2 | IndyCar |
| $3 | 3500 |
| $4 | MotoGP |
| $5 | 990 |
となります。よく分からなかった方、グループと各文字列を見比べて動作を理解してください。
グループを使った拡張表現です。
「(?#」の後、「)」が出現 するまではコメントとして扱い、マッチングには使いません。
Perlでは、正規表現を複数行に分けて記述できますので、各行にこのような形でコメントを 埋め込んでいることが多いようです。
K2Editorでは複数行に分けることは出来ませんから、 使えなくは無いですが見難くなってしまうでしょう。
通常、グループ化すると後方参照用にキャッシュされますが、 「(?:…)」のようにすると、キャッシュされなくなります。 この場合、後方参照ではつかえません。
たとえば「\b(\w+)(?:\d+)(\w+)\b」では英単語の中に数字を 含むものがマッチしますが、後方参照できるのは英字部分だけになります。
Bin2Hex
に対して検索した場合、各$Xは以下のようになります。
| $1 | Bin |
|---|---|
| $2 | Hex |
| $3 | なし |
このように「(?:…)」で囲った部分は参照できません。 番号も2番目のグループは無いものとして振られています (3番目のグループが$2になる)。
通常、非格納グループを使った方が動作は速くなるようです。キャッシュも減りますので、 メモリ使用量も多少減ります。 効率を求めるなら積極的に使うべきかも知れませんが、 通常はあまり気にする必要は無いと思います。
「(?=pattern)」はゼロ幅の肯定的先読み表現です。 といっても理解できないと思いますが(私も含めて)。
たとえば、ファイルのリストから「[^\\]+(?=\.txt)」 で検索を行えば、拡張子がtxtのファイルのファイルタイトルだけを抽出できます。
このように、「hoge(?=pattern)」で patternが後に続くhogeにマッチします。
「(?!pattern)」はゼロ幅の否定的先読み表現です。
「hoge(?!pattern)」のとき、 patternが後に続かないhogeにマッチします。
ファイルのリストから「[^\\]+(?=\.(?!txt))」 で検索を行えば、拡張子がtxtでは無いファイルのファイルタイトルだけを抽出できます。
厳密にいえば、上記の説明は正確とは言えないかもしれません。 ‘ゼロ幅’と言うのがうまく説明しきれていないからです。 ただ、これを説明すると余計に混乱する可能性があります。 混乱したくない方はこの後しばらくを読み飛ばしてください。
「(?=pattern)」は ‘pattern’が続く位置にマッチします。 つまり、この正規表現はアンカーです。 厳密にいえばグループではないと言うことになります。
この正規表現が示す位置はpatternの直前です。 「(?=\.txt)」であれば ‘.’の直前の位置になります。 「(?!\.txt))」であれば ‘.’では無い文字の前です。
これは、「[^\\]+(?=\.txt)\n」 はマッチさせることが出来ないことを意味します。 なぜなら、「(?=\.txt)」 がマッチするのは‘.’の直前の位置ですから、 その直後に「\n」が無くてはいけないのですが、 マッチ直後は必ず‘.’があります。 絶対にマッチしないと言うことになります。
したがって、この後説明する「後読み(lookbehind)」の代わりにはなりません。
この機能はK2Editorでは使用できません。 使っているライブラリが対応していないからです。 Perlの最新版では使えます。
先読みとの関連で一応説明しますが、無駄なことは覚えたくない方は (そうではない方も)読み飛ばして頂いてかまいません。
Perlでは 「(?<pattern)」でゼロ幅の肯定的後読み、 「(!<pattern)」でゼロ幅の否定的後読みになります。
「(?<pattern)hoge」は patternが前にあるhogeにマッチし、 「(!<pattern)hoge」は patternが前に無いhogeにマッチします。 両方とも、マッチするのはhogeで、patternは含まれません。
先読みを使った「(?=pattern)hoge」 が「(?<pattern)hoge」 とは違うのは、この動きをみると分かります。
RX-3 RX-7 RX-8
に対して、「(?<RX)-\d」を検索すると、
-3 -7 -8
がマッチします。
「(?=RX)-\d」では何もマッチしません。
これは 「(?<RX)」がマッチするのは RXの後なのに対し、 「(?=RX)」がマッチするのは RXの前であるからです。
「(?=RX)-\d」の場合、 「(?=RX)」がマッチすると、 次の比較はRXの前から始まります。 「-\d」はRXの後ですから、当然マッチしません。
「(?=RX)RX-\d」であればマッチしますが、 これは「RX-\d」と等価です。 マッチする文字列にはRXも含まれます。
先読みと後読みは違う(先読みは後読みの代わりにはならない)というのは、 このような動作の違いからくるものです。