woshidan's blog

そんなことよりコードにダイブ。

今日からはじめよう、正規表現 in Ruby (量指定子編)

量指定子で○○〜○○まで、の〜〜を取得する

 

今日は量指定子についてやります。

たとえば英数字が何文字か続いた後 (英数字以外も来るけれど)に

@マークが来るというのを正規表現で表すときとかに、量指定子を使います。

 

初心者:えーと.+,.*とかでしょう。

 

.は「改行以外の任意の一文字」を表すメタ文字ですね。後ろは合ってます。

繰り返しをさせたいグループや文字クラスの後において使います。

 

さて、量指定子を表すメタ文字には以下の種類があります。

  • * 0回以上
  • + 1回以上
  • ? 0回もしくは1回
  • {n} ちょうどn回(nは数字)
  • {n,} n回以上(nは数字)
  • {,m} m回以下(mは数字)
  • {n,m} n回以上m回以下(n,mは数字)

 

このへんは、どれがどれか分からなくなったら検索しながらでも使ってもいいでしょう。

文字クラスやキャプチャ、アンカーあたりはややこしくてよくわからない人はいるけれど、量指定子が後ろにおいて繰り返しを見るために使う、

という点は、みんななんかわかっている感じがします。感覚的に。

 

自分の場合、たまにやるのは*,+を混同して、以下のようになってしまったりします。

 

*は 0回以上の繰り返しだから、<div>のvの後ろにすぐ>がきてタグを閉じている場合も検出できているけれど、

+はdiv id="..."みたいにvの後にすぐ>が来ない場合しか検出できてませんね。

 

あと回数を指定してマッチが出来るというのは人によっては使ったことがないかもしれませんね。+や*でこと足りることが多いので。

 

初心者:あれ、動かない!

 

 

それは、こうですか? たまに忘れますけど、コンピュータにとって空白や改行は文字ですからね。

 

 

空白文字については言語や文字コードの問題で\sのほうがいい場合もあるかもしれませんね。

まあ、入力して駄目だったとき入力し直したらいいと思いますよ。

 

初心者:そういえば、これ({})、いつ使うんですか?

あと、後ろに今回は1:って出てますよね。

 

ああ、二つ目の疑問については、あとでキャプチャについての話で答えます。

 

で、{}についてですが、これはidとかで、データの長さが決まっているものを取り出すとき、

文字の種類の後に空白、とやるかわりにその文字種の繰り返し回数を指定して長さを書いてやる、という感じです。

たとえば、以下の例ではid:の後に数字が何回か来る、という上の正規表現でもidを取り出せるけど、

idが6桁だと決まっていたら下の数字6桁の列でも取り出せるし、こっちはidだけ取り出せていますよね。

 

任意の回数繰り返しだと、生年月日とか他の数字の並びを引っ掛けちゃう可能性があるので、

そういうとき便利かもしれません。

 

 

 

初心者:そーいえば、さっきメタ文字ってわざわざつけたということは、

                 量指定子って、他に気にすることがあるんですか?

 

そう、それです。

量指定子には最大量指定子と最小量指定子の二種類があります。

最大量指定子はなるべく文字数が多くなるように、

最小量指定子はなるべく文字数が少なくなるようにマッチングを行います。

 

初心者:えーと、よく意味わかんないです。

    どう使えばいいんです?

 

そうだね、じゃあ、次のリストのタグをマッチングする事を考えましょう。

 

初心者:……

 

期待通り、げっそりしてくれてありがとう。

さて、どうしましょうか。

 

複数行にマッチする正規表現

初心者:いや、量指定子とかの前にマッチする文字列の中に改行が入ってたらよくわかんなくなるんですけど。

 

ああ、そういえば、そうですね。

改行自体、改行(\n)でマッチできることがわかっていても、

量指定子でマッチする部分の中に改行が入っていたらよく分からなくなることありますね。

 

改行の部分もマッチに含むにはいくつか方法があって、

私がよくやるのは、

[\s\S]か.が入っている正規表現にmオプションをつけることですか。

 

前者は空白と空白以外の文字のどちらかがきたらマッチする、という意味で、ようするにどんな文字でもマッチすることにしてしまう。

別にsであることに意味はないし、これはオプションになれてないから回避したいだけでいい習慣ではありませんね。入力が楽なだけです。

 

初心者:あれ、いちおう講師なのにいいんですか。

 

試しに入力するときくらい好きにさせてください。よくないけど。

で、/mっていうのは、.を改行にもマッチするようにつけるオプション

例を並べてみましょう。オプションについては、後でやるか、忘れていたら、自分でやって。

 

 

初心者:おー、説明受けてから見るとなんか分かりやすいです。

 

それは何より。

 

最大量指定子と最小量指定子

量指定子の最大量指定子、最小量指定子をきちんと理解すると、

htmlのタグのネスト構造なんかをうまく取り出すことが出来ます。

 

初心者:あ! テキストエディタの色がつくやつですね!

 

まあ、それ以外にもいろいろあると思うけど、たぶん使われてるでしょうね。

最大量指定子、というのは、普段から使っているものがそうですね。

 

では、最小量指定子の説明をしましょう。

 

 

上の二つの量指定子(+)の後ろを見てください。

二つ目は+の後ろに?がついていて、そうすると、マッチした文字列が短くなっていますね。

この?がついた量指定子のことを最小量指定子といいます。

 

さて、最小、という部分を説明します。

<ul>タグから</ul>タグまでを取り出してください、と言われたらどうしますか。

 

初心者:どうしますか?

    と言われても……。えー、最初と最後のタグ……って、終了タグ二カ所あるじゃないですか、これ。

 

そうですね。

 

ここで、普通の量指定子なら、可能な限り量指定子の部分にマッチする文字列が多くなるようにマッチします。

<ul>任意の文字列</ul>にマッチする部分は

<ul>\n  <li id=\"first\">テキスト</li>\n  <li id=\"second\">テキスト</li>\n</ul>

のsecondの後の最初のulで切れる場合と、

<ul>\n  <li id=\"first\">テキスト</li>\n  <li id=\"second\">テキスト</li>\n</ul>\n<ul>\n  <li id=\"third\">テキスト</li>\n  <li id=\"fourth\">テキスト</li>\n</ul>">

の最後の</ul>で切れる場合がありますが、

この普通の量指定子の場合だったら、後者とマッチします。

これを、最大量指定子といいます。

 

で、量指定子の後ろに?をつけて最小量指定子にした場合、

最初に量指定子の後ろの部分にマッチするものが出て来たら、量指定子の部分のマッチをそこで終了します。

だから、上の例だと、最小量指定子にした場合、secondの後の</ul>でマッチが終了します。

 

ここ(http://docs.ruby-lang.org/ja/1.9.3/doc/spec=2fregexp.html)の例だと、

 

 

で、.は改行以外の任意の文字にマッチするので、数字にもマッチします。

だから、上はなるべく多くの文字にマッチしようとして201まで最初の.の部分でマッチしています。

だから、\dにマッチしている部分が3しかありません。

下は、.*に?がついているので、数字が来た時点で.*のマッチが終わり、\dとしてマッチする部分が

2013に変わっています。

 

あ、そうそう、\dの後ろの+も量指定子だから、長くなるようにとらないのか、という話ですが、

この欲張りなマッチングの欲張りの優先度は左に来ている量指定子が上です。

この、先着順の欲張りを、自分にマッチした文字が来たら止めさせるのが最小量指定子の?なんですね。

 

だから、繰り返しになりますが、

下では数字の2が来た段階で.*の部分のマッチを止めていて、2013が(\d+)の部分としてマッチしています。

 

バックトラック

初心者:バックトラックってなんですか?

 

一回欲張りで最大限にマッチさせたあと、後ろの正規表現とマッチするものがなくならないように、

前の正規表現がマッチする部分を縮めること、かな。自信ないですけど。

 

たとえば、上のCopyrightの例だと.*だけなら最後の.までマッチできるのだけど、

それだと(\d+)\.とマッチできなくなるから、「3.」の部分は.*とマッチしない部分にしていますね。

これは、.*だけの場合よりもマッチしていた部分が縮まっている事になりますが、分かりますか。

 

まあ、こんな説明よりここの説明が分かりやすかったでしょうか。

欲張り正規表現 - Atzy->getLog()

 

ここを理解して、機会があったら絶対最大量指定子にも挑戦してみますか?

 

初心者:いや、いいです。私ちょっと今日は頭いたいので、帰ります。