雑文発散

«前の日記(2008-02-12) 最新 次の日記(2008-02-14)» 編集
過去の日記

2008-02-13 [長年日記]

[PHP][Perl][Ruby] PHP / Perl / Ruby での正規表現の挙動の違い #2

hnw さんからツッコミを貰ったので、昨日のコードをちょっと改造して、マッチしている部分をチェックしてみた。

PHP のコード。test.php。

#!/usr/bin/php
<?php
 
$array = array('1234',
               '1234' . "\n",
               '1234' . "\n" . '5678');
 
for ($i = 0; $i < count($array); ++$i) {
    if (preg_match('/^([0-9]+)$/',$array[$i],$match)) {
        print "ok: " . $match[1] . "\n";
    } else {
        print "ng\n";
    }
}
?>

Perl 版。test.pl。

#!/usr/bin/perl
  
@array = ('1234',
          '1234' . "\n",
          '1234' . "\n" . '5678');
 
for ($i = 0; $i < @array; $i++) {
    if ($array[$i] =~ /^([0-9]+)$/) {
        print "ok: " . $1 . "\n";
    } else {
        print "ng\n";
    }
}

Ruby 版。test.rb。

#!/usr/bin/ruby
 
array = ['1234',
         '1234' + "\n",
         '1224' + "\n" + '5678'];
 
array.each { |tmp|
   if /^([0-9]+)$/ =~ tmp then
      print "ok: " + $1 + "\n"
   else
      print "ng\n"
   end
}

で、実行結果。

$ ./test.php 
ok: 1234
ok: 1234
ng
$ ./test.pl  
ok: 1234
ok: 1234
ng
$ ./test.rb
ok: 1234
ok: 1234
ok: 1224

PHP / Perl / Ruby とも文字列の末尾に「\n」が入っているいないに関わらず同じ結果になった。文字列中に「\n」が入っている場合、Ruby だけが 1234 にマッチしていた。

これはつまり、Ruby における正規表現は PHP / Perl での m オプション付きと同じ動きなのかしら?

ということで、オプションを付けて実行してみた。

#!/usr/bin/php
<?php
 
$array = array('1234',
               '1234' . "\n",
               '1234' . "\n" . '5678');
 
for ($i = 0; $i < count($array); ++$i) {
    if (preg_match('/^([0-9]+)$/m',$array[$i],$match)) {
        print "ok: " . $match[1] . "\n";
    } else {
        print "ng\n";
    }
}
?>

#!/usr/bin/perl
 
@array = ('1234',
          '1234' . "\n",
          '1234' . "\n" . '5678');
 
for ($i = 0; $i < @array; $i++) {
    if ($array[$i] =~ /^([0-9]+)$/m) {
        print "ok: " . $1 . "\n";
    } else {
        print "ng\n";
    }
}

$ ./test.php
ok: 1234
ok: 1234
ok: 1234
$ ./test.pl
ok: 1234
ok: 1234
ok: 1234

この結果だけみると、PHP / Perl と Ruby とで同じ状態にはなったんだが、「Ruby の正規表現は Perl における m オプション付きがデフォルト動作」という認識は正しいのだろうか?

本日のツッコミ(全3件) [ツッコミを入れる]
たかはし (2008-02-14 00:40)

えー、Perlのmオプションについては良く知らないのですが、Rubyでは$は行末にマッチであり、文字列末尾ではありません(文字列末尾は\z)。<br>↓このページが詳しいかも。<br>http://jp.rubyist.net/magazine/?0021-BundledLibraries

hnw (2008-02-14 01:36)

思いつきレベルでコメントさせて頂いたんですが、解決したみたいですね。<br><br>\zはPerl 5.005から導入されているそうです。また、\Zってのもあるそうで。僕は随分昔からPerlをやってるはずなんですが、恥ずかしながら先ほど知りました。<br><br>$は0文字にマッチするような気がしちゃうんですけど、実は文字列最後の\nに限っては1文字にマッチするんですよね。-peしたときにchompしなくてもsedと同じ動作をさせるようなPerlの発明なのかもしれませんが、それだと不便な人もいるから行末や文字列末尾の0文字にマッチする記号が導入されたんでしょうかね。

hnw (2008-02-14 01:48)

すみません、誤解してました。やっぱり$はいつでも0文字マッチなんですね。普段は最後の文字の次の0文字にマッチ、文字列最後の文字が\nのときだけ\nの直前の0文字にマッチ、なんですね。今までずっと誤解していたようです…。