正規表現道場 Part2 (393レス)
上下前次1-新
抽出解除 レス栞
リロード規制です。10分ほどで解除するので、他のブラウザへ避難してください。
112(2): 2014/02/02(日)07:59 ID:??? AAS
う〜ん、/g はループなのに break する方法が用意されていない。
COMMIT があるのにこれがないのはとても不可解だ。
# 先読みの中の (*SKIP) は機能しない。
@test = $_ =~ m/1|2(?=.*(*SKIP))|3/g;
# while 文の last を使う。
$_ = "123";
while ( m/1|2|3/gp )
{ print "${^MATCH}\n";
last; } # 1 で止まる。
# (?{code}) で last → 効果なし
while ( m/1|2(?{ last; })|3/gp )
# while 文に名前を付けて (?{code}) で last → 効果なし
TEST : while ( m/1|2(?{ last TEST; })|3/gp )
perl陣営に言えば新しいコマンド作ってくれそうだなぁ。
114(1): 2014/02/02(日)10:19 ID:??? AAS
>>111
>>112 >>123
/g がループというのはちょっと違う.
リストコンテキストで評価したときはループと言えるが,スカラーコンテキストで評価したときはループではなく,
単に前回マッチした場所を覚えていて続きからマッチングを行うというだけ.
この問題はリストコンテキストで /g を評価したときに,マッチ成功後に途中で止めるいい方法はないかって言う問題だと解釈した.
スカラーコンテキストで評価したときに止めるんなら last を使えば簡単に止まる話.
つまり,while を使っていいんなら,
while (/1|2(*:STOP)|3/g) {
push(@test, $&);
last if $REGMARK eq 'STOP';
}
print "'@test'\n";
リストコンテキストで評価したときに途中で止めるには,かなり条件が限定されるが,
@test = $_ =~ m/(?(?<=2)\G(*COMMIT)(*FAIL))(?:1|2|3)/g;
ぐらいしか思いつかなかった.
これではフラグを使った方が簡単だろう.
121: ◆QzqhRqBYxktP 2014/02/03(月)07:41 ID:??? AAS
↑× /p のマッチング中に → /g の間違い
----------------------------------------------
# 先読みの中の (*SKIP) は正しく機能する。(× >>112)
$_ = "123";
@test = $_ =~ m/1|2(?=.*\z(*SKIP)(*F))|3/g;
print "@test\n";
# 結果 → 1
# 先読みの中の (*SKIP) が失敗する例もある
@test = $_ =~ m/1|2(?=.*\z(*SKIP))(*F)|3/g;
# 結果 → 1 3
# perl内部の最適化の影響により (?=) より早く (*F) が判定されている?
# $REGERROR が期待通りに動かない原因も最適化が犯人? (最適化は 詳説 正規表現 参照)
----------------------------------------------
# \z で始まる正規表現 + while( /g )
while (
m/\z(?{ print "in code\n"; })/g
)
{ print "match!\n"; }
<結果>
in code
match!
in code
2回走査されてる。2回目は走査しといてマッチ失敗。/g により1つ先に進む動作の副作用?
(?{code}) が2回実行されるのでプログラムが想定外の動作になる可能性。
/g を忘れると走査開始位置が毎回先頭に戻り、無限ループになる。
上下前次1-新書関写板覧索設栞歴
スレ情報 赤レス抽出 画像レス抽出 歴の未読スレ AAサムネイル
ぬこの手 ぬこTOP 0.027s