うまいぼうぶろぐ

linuxとhttpdとperlのメモ

文字列から特定桁の数字を抜き出す

project eulerの8問目を見てて、ふと疑問に思った。

この場合、まず数値列(文字列)から全ての5桁の数字を取ってきたいとする。簡単にするために、20桁の数値列で考える。

$str = '0123456789' x 2;
while ($str =~ m/(\d{5})/g) {
  print $1, "\n";
}

これだと、5桁の数字が

01234
56789
01234
56789

こう出てくるんだけど、そうじゃなくて

01234
12345
23456
34567
45678
56789
...

ってやるにはどうしたらいいんだろう。

追記 (一応解決した)

pos関数でマッチしたオフセットをシフトさせればいいのかな。

$str = '0123456789' x 2;
while ($str =~ m/(\d{5})/g) {
  print $1, "\n";
  pos($str -= 4;
}

とやって、マッチする毎にオフセットを4つ前に戻せば望み通りのことはできました。なんだかad hocな感じがするけど :-)

追記2

commentでツッコミいただいたのでsubstrでやってみる。
こんなのでいいですか><

$length = length $str;
for $i (0..$length) {
  $num = substr($str,$i,5);
  next if $num =~ m/\D/;
  last if length $num != 5;
  print "$num\n";
}

追記3

いやいや、こんなことしなくても正規表現で先読みすりゃいいだけじゃないか。

$str = '0123456789' x 2;
while ($str =~ m/(?=(\d{5}))/g) {
  print $1, "\n";
}

先読みでゼロ幅だからマッチ位置は変わらないけど、/gがあるのでループごとに1つ進む。