![](http://oshiete.xgoo.jp/images/v2/pc/qa/question_title.png?e8efa67)
正規表現の質問です。
言語は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個の変数に対応しているのです。
どういうことなのでしょう。
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回目以降も「偶然、マッチしてしまっただけ」です。
なるほど、件の正規表現から前方参照を削除した
$http{BODY}=~ /(?<=\[ No\.)([0-9]{$digit})/o;
の結果を見てみると、最初の$digitが1だと、他のファイルでも全て1桁の数字しかマッチしていませんでした。
うまく作動していると思われる o オプションは、全てs///の構文で用いたものでした。
もう一度調べなおすと、
s/Pattern/Replace/o
の構文では、Replaceにある変数は書き換えられるようですが、Patternにある変数は書き換えられませんでした。
ありがとうございました。
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 をつけたり消したりすると動作が変化します.
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- システム CSVファイルのマッピング処理の省力化 1 2022/11/24 00:01
- その他(IT・Webサービス) ホームページにカウント数を表示する 2 2022/10/28 10:37
- PHP PHP MySql ページング 2 2022/09/20 06:38
- 統計学 確率統計の問題です。 3 2022/04/07 04:39
- 数学 正規数の定義で分からないことがあります。 正規数の定義について専門書において 「xがr進正規であると 1 2023/07/17 20:50
- 数学 参考文献の探し方(数学) 1 2022/07/19 01:09
- Excel(エクセル) エクセルでSUMIFS関数で条件範囲の部分が#valueになる。 4 2023/04/28 12:42
- Visual Basic(VBA) 3つのプロシージャをまとめたら実行時エラー発生で対応不能 6 2022/05/17 01:47
- Visual Basic(VBA) 【VBA】写真の縦横比を変えずに貼り付ける 5 2023/06/13 11:42
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
Tinderのマッチングアプリ辞め...
-
正規表現
-
正規表現の ^
-
CSVファイルの中で、「 , 」カ...
-
英数字のみ全角から半角に変換
-
エクセルで数値を全角文字(カ...
-
VBA EXCEL あるセルの中の一...
-
EXCELからCSVにすると余計なカ...
-
「何とかで始まり、何とかで終...
-
VBA 置換文字がみつからない時
-
文字コードの%E3%80%とは何です...
-
マクロを使ってフォルダー内に...
-
csvデータ ダブルクォーテ...
-
COBOLでの全角文字の判定をした...
-
住宅にカナを入力する際に丁目...
-
C#で、テキストボックスの入力...
-
データにカンマが入ったCSVデー...
-
[VBA][Excel]クリップボードか...
-
IEからEdgeへの移行に伴うIMEの...
-
スペースで区切られた氏名から...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
正規表現 URL抽出「 [\\/\\b]{0...
-
シェルスクリプト [[ $number =...
-
正規表現について VB6
-
正規表現について
-
日本語環境下でのバックスラッ...
-
正規表現で2種類ある括弧を区別...
-
perlの正規表現で量指定子を繰...
-
perl初心者です。
-
言語ではなく、正規表現のみで...
-
正規表現の展開
-
正規表現
-
正規表現について教えてください
-
正規表現が解読できません。
-
pythonの正規表現、全角カタカ...
-
行末の正規表現について。
-
正規表現。行頭が○○以外にマッ...
-
配列内の要素をパターンマッチする
-
置き換えについて
-
【GVimの正規表現における検索...
-
「?」が含まれるマッチについて
おすすめ情報