アプリ版:「スタンプのみでお礼する」機能のリリースについて

m//gとm//gcにはどんな違いがあるのでしょうか。

いくつか解説を見たのですが、どれも「m//gではマッチに失敗すると通常は文字列の検索位置が文字列の先頭にリセットされるが、cをつける (m//gc) と、これを防ぐことができる」のような感じでさらっと説明されていて、イマイチ理解できません。スクリプトを適当に作成して試してみたのですが、cをつけてもつけなくても結果は変わらないような気がします。これは、つまり、cがあるときと無いときの違いは、効率の違いとして現れるだけで一般的にはcをつけておけばいいと考えていいのでしょうか。
http://perldoc.jp/docs/perl/5.6.1/perlop.pod#ite …

以下のスクリプトはindex関数的に配列@strの各要素文字列に含まれる検索文字列$findwordの位置を表示させるものですが、やはりcをつけてもつけなくても結果は変わりませんでした。

my @str = ('pattern match', 'at random', 'exponentiation operator');
my $findword = 'at';
my $len = length $findword;
print "search '$findword'\n\n";
foreach my $str (@str) {
my $count;
print '0123456789' x 3, "\n";
print "$str\n";
{
if ($str =~ /$findword/ogc) { printf("match%d: %d\n", ++$count, pos($str)-$len) }
else { print "\n"; last }
redo;
}
}

# /oはパターン内の不変変数を一度コンパイルすれば十分というものです

A 回答 (2件)

#以下を試してみたらわかりやすいかも


$text="bbb ddd 111 222 333";
print "option:g\n";
$text=~ /[a-z]+/g; print pos($text).":$&\n";
$text=~ /[a-z]+/g; print pos($text).":$&\n";
$text=~ /[a-z]+/g; print pos($text).":$&\n";#リセットされる
$text=~ /[a-z]+/g; print pos($text).":$&\n";
$text=~ /[a-z]+/g; print pos($text).":$&\n";
pos($text)=0; #reset
print "option:gc\n";
$text=~ /[a-z]+/gc; print pos($text).":$&\n";
$text=~ /[a-z]+/gc; print pos($text).":$&\n";
$text=~ /[a-z]+/gc; print pos($text).":$&\n";
$text=~ /[a-z]+/gc; print pos($text).":$&\n";
$text=~ /[a-z]+/gc; print pos($text).":$&\n";
    • good
    • 0
この回答へのお礼

回答していただき、ありがとうございます。
なるほど!このコード、とてもわかりやすいです。入門書などで下手にループとか使わずに、うまく説明されていたのを思い出しました。ループ処理には無関係で、マッチ変数にはこんな風に記憶されているんですね。

# すみません。ポイントの大小気にしないでください。とても感謝しています。

お礼日時:2005/12/13 15:56

gオプションにはパターンにマッチした部分を対象文字列から順次抜き出す機能があります。



@ary = $str =~ m/PATTERN/g;

とすると、$strからPATTERNにマッチする部分を全部抜き出し、配列に入れることができます。また、

$scl = $str =~ m/PATTERN/g;
とすると、マッチした文字列を一つずつ抜き出します。
$strがPATTERNにマッチすると1を返し、マッチした部分の次のインデックスをpos($str)関数で取得できます。
再度同じ文字列をm//gでマッチングするとき、pos($str)の位置から検索されます。
これ以上マッチする文字列が見つからない場合、pos($str)は先頭位置にリセットされます。
が、m//gcでは先頭位置にリセットされずに、一番最後にマッチしたインデックスがそのまま残ります。

以下のスクリプトを実行すると挙動が理解できると思います。

$s = 'hat hit hut het hot';

print "case m//g\n";
#マッチできなくなるまでループさせる
while(my $r = $s =~ m/(h.t)/g)
{
print pos($s)."\n";
}
#マッチできなくなったあとのposを取得
print 'lastpos' .pos($s)."\n";

print "case m//gc\n";
while(my $r = $s =~ m/(h.t)/gc)
{
print pos($s)."\n";
}
print 'lastpos' .pos($s) ."\n";


cオプションをつけただけで効率が変わることはないと思います。
kapuraさん添付のソースでは、各文字列に対し一度しかマッチングさせていないので、cはつけてもつけなくてもいいでしょう。
    • good
    • 0
この回答へのお礼

回答していただき、ありがとうございます。
直接の質問以外の点も説明していただいて、頭の整理ができました。示していただいたコードもわかりやすく、理解するのに役立ちました。

つまりcオプションをつけないつけるは、posで返される値をリセットするかしないかということで、もしループ処理の後で最後にマッチした位置を使う場合にはcオプションをつければいいと考えればいいのかな。

ということは、質問内で示したスクリプトは、else節を
else { printf("laspos: %d\n\n", pos($str)); last }
としたら違いが出るのかなと思って試したら、確かに結果が変わりました!

if節を囲む裸のブロックの部分は
while ($str =~ /$findword/og) { printf("match%d: %d\n", ++$count, pos($str)-$len) }
などと書いてもいいんですね。

# 理解が間違っていなければいいんですが・・このまま質問を締め切りたいと思います。このまま続けても感謝のポイントをさらに追加で渡すことができないので。

お礼日時:2005/12/13 15:55

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!