正規表現の o オプションの意味とは?

このQ&Aのポイント
  • 正規表現の o オプションは、変数展開を1回だけ行うという意味です。
  • o オプションを付けた正規表現では、正規表現を処理するためのメモリ領域に一度変数の値を取り込むため、変数の値が変わってもメモリ領域の値は変化しません。
  • 正規表現の変数を1つだけ使用する場合でも、o オプションを付けることで効率的に処理が行われます。しかし、変数が複数ある場合は考慮が必要です。
回答を見る
  • ベストアンサー

正規表現の o オプションの意味が分かりません

正規表現の質問です。 言語はPerlで組んでいます。 いくつかのhtmlファイルを順に開き、以下のようなコードを実行します。 $http{BODY}=~ /(?<=\[ No\.)([0-9]{$digit})(?= \/ $num)/o; ここで $http{BODY} 読み込んだhtmlファイル $digit 変数。整数値。 $num 変数。整数値。 この正規表現で、 ・・・・[ No.2 / 3 ]・・・・ といった感じの文字列から、この場合は「2」をマッチさせようとしました。 ところが最初に読み込んだファイルではうまくマッチしたのですが、2番目のファイルではマッチしません。 o オプションを外すとうまくいきました。o オプションは変数展開を1回行うとのことです。元のファイルはやたらとでかいので、o オプションを付けたら少しは早くなるかなと思いつけていたのですが。。。 ネットで調べると、 while( $s = <FH> ){ # 一度だけ展開する if ( $s =~ /$arg/o; ){ .... } このような用例で、$argは変数というよりも、セットされた文字列として評価されるとあります。でも前述の正規表現の2つの変数、$digitと$numは普通に値を書き換えられていましたけど。。。 それとも o オプションを付けた正規表現では、その正規表現を処理するためのメモリ領域に一度変数の値を取り込むと、二度と読み込むことをしないということでしょうか。だから変数の値が変わっても、正規表現が用いるメモリ領域の値は変化しない。。。 でも $http{BODY}=~ /(?<=\[ No\.)([0-9]{$digit})/o; だったらちゃんと$digitの値が変わったことに対応しているんです。他にもいっぱい o オプションを付けた正規表現を用いていますけど、全部正常に作動しています(バグに気づいていないだけかもしれませんけど)。 前述の正規表現とこれら正常に作動する正規表現の違いは、後者が変数1個であるのに対して、前者は2個であるということです。「変数展開を1回行う」の意味は、変数1個にしか対応しないという意味なのでしょうか。でも前者も最初のファイルだけなら2個の変数に対応しているのです。 どういうことなのでしょう。

  • Perl
  • 回答数2
  • ありがとう数3

質問者が選んだベストアンサー

  • ベストアンサー
  • chie65535
  • ベストアンサー率43% (8526/19383)
回答No.1

oオプションは「変数展開を最初の1回だけ行う」です。 一度でも $http{BODY}=~ /(?<=\[ No\.)([0-9]{$digit})(?= \/ $num)/o; を実行すると、実行した時点の値で、正規表現が固定されます。 例えば、$degitが「1」、$numが「2」の状態で、上記の行を1回でも実行すると、その行は、それ以降 $http{BODY}=~ /(?<=\[ No\.)([0-9]{1})(?= \/ 2)/o; として動作します。 2回目の実行前に、$digitや$numの値を変更しても、それは反映されません。これらがどんな値になってようが $http{BODY}=~ /(?<=\[ No\.)([0-9]{1})(?= \/ 2)/o; として動作します。 例えば $digit=1 $num=1 while( $num < 10) {   $http{BODY}=~ /(?<=\[ No\.)([0-9]{$digit})(?= \/ $num)/o;   .....   $num++; } とやっても   $http{BODY}=~ /(?<=\[ No\.)([0-9]{1})(?= \/ 1)/o; が9回行われるだけです。 怖いのは「ループカウンタとして$numは9まで増えて9回ループして終わるが、正規表現では、ずっと同じ値で処理される」って事です。 デバッグ表示で$numを表示したら、ちゃんと値は変化しているのに、値が変化しない正規表現が繰り返されるのです。 >ところが最初に読み込んだファイルではうまくマッチしたのですが、2番目のファイルではマッチしません。 当たり前です。 $numも$digitも「最初のファイルを読み込んだ時にセットされた値が展開されたあと、二度と評価されない」のですから、最初のファイルと同じ物しかマッチしません。 2番目のファイルを読み込んでも「最初のファイルで行った正規表現で実行する」ので、マッチする訳がありません。 >でも >$http{BODY}=~ /(?<=\[ No\.)([0-9]{$digit})/o; >だったらちゃんと$digitの値が変わったことに対応しているんです。 それは気のせいです。$digitが変化しても再評価されず、ずっと1回目の値で動いているけど、1回目も2回目以降も「偶然、マッチしてしまっただけ」です。

makoji
質問者

お礼

なるほど、件の正規表現から前方参照を削除した $http{BODY}=~ /(?<=\[ No\.)([0-9]{$digit})/o; の結果を見てみると、最初の$digitが1だと、他のファイルでも全て1桁の数字しかマッチしていませんでした。 うまく作動していると思われる o オプションは、全てs///の構文で用いたものでした。 もう一度調べなおすと、 s/Pattern/Replace/o の構文では、Replaceにある変数は書き換えられるようですが、Patternにある変数は書き換えられませんでした。 ありがとうございました。

その他の回答 (1)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

Perl が言語として意図しているのは「それとも」の方です. つまり, //o は「『その正規表現』を最初に使うときのみ変数の値を展開する」ということを指示します. たとえば $m = 10; while ($m > 0) { $s = '1' x $m; if ($s -~ /1{$m}/o) { print "match\n"; } else { print "unmatch\n"; } --$m; } において o をつけたり消したりすると動作が変化します.

makoji
質問者

お礼

サンプルコードのおかげで理解しやすかったです。 ありがとうございました。

関連するQ&A

  • 正規表現について

    あるファイルを読み込んで中に変数($xxx)が入っていたら 正規表現にて$xxxの値に変換する事は出来ますでしょうか? 試行錯誤しているのですが、上手くいかず困っています。 変数を正規表現にてマッチングさせるのも上手くいかないです。 ご教授お願いいたします。

    • 締切済み
    • PHP
  • JavaScriptの正規表現について

    お世話になります。 HTMLでテキストに入力された数値のチェックを下記のようにJavaScriptで行っています。 ---------------------------------------------------------  function check_num(obj) {')   obj_w = document.form_name.elements[obj];')   if(obj_w.value.match(/^\d{0,1}(\.\d{1,3})?$/)){    return 0;   else{    alert("測定値は整数部分1桁、小数部分3桁までの正の数値を入力して下さい。")    obj_w.focus();    return 1;   }  } ----------------------------------------------------------- このとき、チェックする整数部分、小数部分の桁数を変数にして汎用性のある関数にしたいのですが、正規表現のなかで変数を使うにはどのようにしたらよいのでしょうか? よろしくお願い致します。

  • 正規表現について

    正規表現で、最初に出てきた条件に合うものだけマッチさせて置換したく、それ以降に条件に合うものがあってもマッチさせたくないのですが、どうすればいいでしょうか? 現在、オプションはつけてないのですが、最後にマッチしたものがとりだされてしまいます。 ---------------------------------------- s/aaa(.*)ccc/$1/; ・・・・・正規表現 ---------------------------- aaabbbccc : : aaadddccc : aaaeeeccc ---------- だと、eeeに置換されるのですが、bbbに置換したいです。 よろしくお願いします。

    • ベストアンサー
    • Perl
  • 正規表現を教えてください。

    正規表現を教えてください。 C#で正規表現を用いた文字列検索を勉強中なのですが、うまくマッチさせることができません。教えていただけないでしょうか。 検索対象の文字列は下のようになります。 キーワード;値; 文字列中に該当するキーワードが存在する場合に、その値を取得するプログラムを考えています。しかし、私の正規表現では2つ目の「;」を検出してしまい、キーワードのみを取得することが出来ずに困っています。 見当違いの表記をしているとは思うのですがどなたかお助けください。 match = Regex.Match(line, "^(.*);"); C#初心者なものです。

  • 正規表現について

    正規表現について勉強しているのですが、 $aaa = "http://あいうえお.こむ/"; $bbb = "http://www.あいうえお.こむ/"; $ccc = "あいうえお.こむ/"; 同じドメイン名ですが、それぞれ変数に入っている値は違います。 これらのドメイン部分を取り出す正規表現はどのようになるのでしょうか。

    • 締切済み
    • PHP
  • 正規表現について

    以下のようなファイル名にマッチする正規表現は [ファイル名] 20080303_001test.txt 20080303_002test.txt [正規表現] ^20080303_(001|002)test\.txt$ であってますでしょうか。 ※特に()内の、"001"と"002)test\.txt"のどちらかにマッチすれば良いという条件になってないか心配です。 よろしくお願いします。

    • ベストアンサー
    • PHP
  • .htaccessの正規表現

    Perlの正規表現なら少しだけ知っています。 .htaccessの正規表現で、 <Files xx.gif> と <Files 'xx.gif'> は同じですか? <Files "xx.gif"> だと変数展開の動作をしようとするために上記の2つより多少重くなりますか? *.gifとerr.logを1つの<File>タグで記述する場合はどう記述すればよいですか?

  • 正規表現

    if(str.match(/^[-+]?\d+$/)) alert("matched !"); この正規表現(先頭に+か-かをつけてあとは数字という表現です。)で 全体が//で囲まれてますがどうしてでしょうか? オプションとしてgとかiがあるのならわかるのですがないみたいです。 また^と$をつかった表現で例えば^AB$とした場合どうしてACBは含まれないのでしょうか?

  • 正規表現を展開させないで子シェルに渡す

    シェルで、 正規表現が入ってる変数を子シェルに渡したいのですが、展開されてしまいます。 展開しないで渡すには、どうしたら良いのでしょうか? 変数には、 123*.txt や aaa[0-9].txt などが入っています。 宜しくお願い致します。

  • バッチファイルで正規表現を使った置換

    あるテキストファイルにID = 'ME000987654'といった文字列が複数存在します。バッチファイルでME000987654を別の値に置き換えたいのですがやり方が分かりません。 このIDはいつも同じではないので、ID = '.*' のような正規表現を使ってマッチさせてそれをID = '新しいID'のように置き換えようと思うのですがこれはバッチファイルで可能でしょうか。