![](http://oshiete.xgoo.jp/images/v2/pc/qa/question_title.png?e8efa67)
下記のようなプログラムを作成しました。
(Perl のバージョンは 5.8.8 となります。)
for ($i=0; $i<=105; $i++) {
$str1 = "str1";
$str2 = "1234567890str1test";
$str2=~ s/^(\d+)($str1)/test/g;
print $i."\n";
print $1."\n";
print $2."\n";
print $str2."\n";
}
このプログラムを実行しますと、ループが100回実施するまでは $1, $2の値を
取得できるのですが、100回を超えると取得できなくなります。
(上記で行っている置換処理は100回を超えても正常に処理されます。)
質問としましては、この現象は Perl のバグなのでしょうか。
それとも、私の正規表現の書き方に不備があるのでしょうか。
ネットでいろいろ調べてみたのですが、答えが見つからなかったため、
質問させていただきました。
よろしくお願い致します。
A 回答 (6件)
- 最新から表示
- 回答順に表示
No.6
- 回答日時:
for ($i=0; $i<=105; $i++) {
$str1 = "str1";
$str2 = "1234567890str1testtest";
$str2 =~ s/^(\d+)($str1)/test/g;
print $i."\n";
print $1."\n";
print $2."\n";
print $str2."\n";
}
手元に v5.005_53 があるので試したところ、ループの1回目から $1, $2 は取得できないようです。^ と /g の併用は通常意味がないので、考えられていなかったのではないでしょうか。むろん、/mg とすると $1, $2 を取得することができます。
v5.8.x の段階は、直している (仕様変更?) 途中だとも考えることができると思います。質問者のように、気づく方がいるとは予想外でしょうが...。
No.4
- 回答日時:
自分の回答をちょっと修正
> my $str1 = "str1";
> my $str2 = "1234567890str1testtest";
> $str2=~ s/^(\d+)($str1)/test/;
s/^(\d+)($str1)/test/;
↓
s/^(\d+)($str1)/test/g;
3) "1234567890str1test"では$1と$2に値が入り、"1234567890str1testtest"では途中から入らなくなるか
これもよくわかっていないので、参考程度にして下さい。
はじめの方への補足で
> <誤>
> $str2 = "1234567890str1test";
> ↓
> <正>
> $str2 = "1234567890str1testtest";
とのことなので、なぜ2つで違いがでるかおもしろいです。
パターンA: "1234567890str1test"
パターンB: "1234567890str1testtest"
二回目のマッチ対象文字列
パターンA: "test"
パターンB: "testtest"
パターンAは4文字、パターンBは5文字残っています。正規表現/\d+str1/は最低でも5文字必要です。したがってパターンAでは二回目のマッチをせずに終了し、パターンBでは二回目のマッチを(途中から)試行するようになるみたいです。
---
なお、質問者さんの現象は、perl v5.8.0では再現し、perl v5.10.1だと再現しませんでした。
この回答への補足
_--_1l1_1_様
ご回答いただきありがとうございます。
_--_1l1_1_様がNo.2の2) なぜ途中から結果が変ったのかで記載されていた内容について
そういう動きをするんだ。と驚きました。
perl v5.8.0と perl v5.10.1の間で、なにかあったのかもしれません。
リリースノートを確認してみたいと思います。
また、二回目のマッチ対象文字列
パターンA: "test"
パターンB: "testtest"
それぞれの動きの違いについて、_--_1l1_1_様が上記で記載されている
仕組みがあったんですね。
No.3
- 回答日時:
しばらく更新してないActivePerl 5.10.0だけど
まったく問題なく動きます.
NO.1さんと同じ意見です.
ソースを簡略化する時点で何か間違った(実際$str2がちがってたようだし・・
けど,その違いは実行に影響がないと思う)のかも.
バージョンをあげてみるとかやることはあると思う.
もう一つ,ほとんど可能性はないとは思うけど
どのOSだとかの実行環境を考えるとか,
意表ついて実は5.8.8の不具合の可能性もまったくないわけではないから
次のバージョン(5.8.9が5.8系の最後だと思う)リリースノートをみてみるとか.
#あー5.14がでてるんだ・・一気に更新しようかな
ソースを見る限り,おかしなところはないように思うし
s///のgも問題ないはず.
一回目のマッチで$1,$2が定義されるけど
それ以上マッチしないから,$1,$2が上書きされることはないです.
あんまりdebuggerわからないけど
use re 'debug' をつけて
perl -dで実行させたら,正規表現のところで
コンパイル時には
Compiling REx "^(\d+)(str1)"
synthetic stclass "ANYOF[0-9{unicode_all}]".
Final program:
1: BOL (2)
2: OPEN1 (4)
4: PLUS (6)
5: DIGIT (0)
6: CLOSE1 (8)
8: OPEN2 (10)
10: EXACT <str1> (12)
12: CLOSE2 (14)
14: END (0)
floating "str1" at 1..2147483647 (checking floating) stclass ANYOF[0-9{unicode_all}] anchored(BOL) minlen 5
でて,実行時には105回ほど
Guessing start of match in sv for REx "^(\d+)(str1)" against "1234567890str"
Found floating substr "str1" at offset 10...
start_shift: 1 check_at: 10 s: 0 endpos: 10
Does not contradict STCLASS...
Guessed: match at offset 0
Matching REx "^(\d+)(str1)" against "1234567890str1test"
0 <> <1234567890> | 1:BOL(2)
0 <> <1234567890> | 2:OPEN1(4)
0 <> <1234567890> | 4:PLUS(6)
DIGIT can match 10 times out of 214748364
10 <67890> <str1test> | 6: CLOSE1(8)
10 <67890> <str1test> | 8: OPEN2(10)
10 <67890> <str1test> | 10: EXACT <str1>(12)
14 <7890str1> <test> | 12: CLOSE2(14)
14 <7890str1> <test> | 14: END(0)
Match successful!
Matching REx "^(\d+)(str1)" against "test"
String too short [regexec_flags]...
Match failed
こんな風にでてくるから
マッチは期待通りにできてるし,$1,$2の取得も期待通りできてます.
だいたい想像できると思いますが
BOL は ^ (Biginning Of Line)
OPEN1 は最初のキャプチャの (
PLUS は +
でCOLSE1が最初のキャプチャの ) です
BOL(2)ってのは,正規表現の「二文字目」 /が1で^が2と数えてます.
私としては・・・むしろ NO.2氏が現象を再現できたのかなと思ってます.
再現できているなら,何か内部的な問題がある(あった)のかもしれません.
この回答への補足
kabaokaba様
ご回答いただきありがとうございます。
デバッガを入れると、kabaokaba様が記載されているように
出力されるんですね。
詳しい解説ありがとうございます。
こちらの方でver5.10.0でやってみましたところ、正常に動作しました。
kabaokaba様が指摘されているように、ver5.8.8あたりにバグがあるのかもしれません。
リリースノートを確認してみたいと思います。
No.2
- 回答日時:
1) s/^(\d+)($str1)/test/g 実行後の$1と$2は不定
my $str1 = "str1";
my $str2 = "1234567890str1testtest";
$str2=~ s/^(\d+)($str1)/test/;
これを実行するとgオプションがついているので
一回目のマッチ
対象 : "1234567890str1testtest"
$1 = "1234567890"
$2 = "str1"
結果 : 一致
二回目のマッチ
対象 : "testtest"
$1 = ??
$2 = ??
結果 : 不一致
したがって、s/^(\d+)($str1)/test/g 実行後の$1と$2は不定になります。試しにgオプションをはずしてみて下さい。上手くいきます。
2) なぜ途中から結果が変ったのか
この例だと途中から処理の仕方が違うようです。すごい適当な解説な上、私もわかっていないので参考程度にして下さい。
前半
まず、"str1”が"1234567890str1testtest"の最後に含まれる場所をsubstrで調べます。これにより、、1) の二回目のマッチが実行する前から失敗するのがわかるので、二回目のマッチ自体をやろうとしなくなります。したがって、
$1 = "1234567890"
$2 = "str1"
が残ります。
後半
どうやら後半からは、substrで調べるのは無駄と判断したのか、やろうとしなくります。1) の二回目のマッチをやろうとするため、$1と$2が空になります。
$1 = undef
$2 = undef
No.1
- 回答日時:
コードに問題はありません。
こちらでそのコードのみを走らせたところ、
105
1234567890
str1
testtest
まできちんと出力されています。
よって原因はほかのところです。
この回答への補足
tk-is-pg_1206 様
回答いただきありがとうございます。
回答いただいたあとの報告で申し訳ないのですが、
質問で記入しましたコードに間違いがありました。
箇所としては以下の部分です。
<誤>
$str2 = "1234567890str1test";
↓
<正>
$str2 = "1234567890str1testtest";
上記の<正>の場合でも、正常に動きますでしょうか。
また、回答いただいた内容で
>原因はほかのところです。
に関しまして、考えられる原因としてはどのようなものがありますでしょうか。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Visual Basic(VBA) 順列をランダムに発生するプログラム 1 2022/11/16 12:16
- Visual Basic(VBA) VBAで最新のデータを別シートに転記する方法をお教えください。 3 2022/04/07 19:20
- Visual Basic(VBA) VBAで時間(00:00形式)を積算(足し算)したい 1 2022/11/15 17:04
- 数学 領域の問題について質問です。 実数s, tは,s^2+t^2≦1, s≧0, t≧0 を同時に満たし 3 2023/05/18 20:59
- Visual Basic(VBA) ワークシートチェンジで曜日を表示する方法 1 2023/03/04 21:51
- その他(プログラミング・Web制作) VScodeでpythonプログラムの関数を実行したい 2 2022/07/13 19:24
- その他(プログラミング・Web制作) pythonのmap、結果の利用は1度だけ? 5 2022/06/11 12:33
- 工学 ウィーンブリッジ発進回路 2 2022/07/16 19:26
- Visual Basic(VBA) 2つのシートの任意のセルの番号が一致したら、一致した行をコピーする VBA 2 2023/06/19 20:48
- C言語・C++・C# バイナリファイルをコピーするのにかかる時間を測りたいのですが実行するとFatel error:gli 2 2022/11/03 01:10
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
テキストファイルで提出とは?
-
ファイルをディレクトリ分配の...
-
openした後、closeしないでプロ...
-
perlのプログラミング 部分入れ...
-
Perlのエラーについてご教授く...
-
画像が表示でnull; this.src
-
perlプログラミング 空白行削除
-
Perlで特定文字列から特定文字...
-
ラズベリーパイ初心者です。 ラ...
-
アルファベットに付いて質問し...
-
#!/usr/bin/perlで書きだしたCG...
-
perlのflock関数でロックをかけ...
-
AI sisterとは、偽物の人ですか?
-
bashスクリプト
-
ファイルアイコンの左下に緑の□...
-
perlでリテラル値はメモリにど...
-
perlで2次元配列をサブルーチ...
-
Perlで時間の計算
-
perlについて
-
perlのrequireの動き方について...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
openした後、closeしないでプロ...
-
テキストファイルで提出とは?
-
INDIRECT 横に再度抽出したい
-
Perlで特定文字列から特定文字...
-
perlをバージョンアップしたら...
-
Wallpaper Engineでおすすめの...
-
arduino の割り込み処理について
-
アルファベットに付いて質問し...
-
Strawberry Perl for Windows ...
-
Perlで時間の計算
-
このファイルを開く方法で困っ...
-
TeraPadエディターの操作方法に...
-
cgiでサーバーにファイルを追加...
-
フローチャート 九九
-
LinuxにおいてのPerlのプログラ...
-
perl 初等プログラミングについて
-
Perlのエラーについてご教授く...
-
こんにちは ブラケッツでプログ...
-
bashスクリプト
-
perlプログラミング 空白行削除
おすすめ情報