『初めてのPerl』第8章 正規表現によるマッチ

ドット(.)をあらゆる文字にマッチさせる/s:
#!/usr/bin/env perl
use v5.12;
use warnings;

$_ = "I saw Barney\ndown at the bowling alley\nwith Fred\nlast night.\n";
if (/Barney.*/) { # こっちはマッチしない
    say "matched";
}
if (/Barney.*/s) { # sを付けると、.は改行文字にもマッチするようになる
    print "That string mentions Fred after Barney!\n";
}
正規表現中に空白文字を含める/x:
#!/usr/bin/env perl
use v5.12;
use warnings;

$_ = "I saw Barney down at the bowling alley with Fred last night.";
if (m{
    Barney
    .* # 正規表現中のコメントは空白文字とみなされる
    Fred
    }x) {
    print "That string mentions Fred after Barney!\n";
}
括弧による文字列のキャプチャと、その制御:
#!/usr/bin/env perl
use v5.12;
use warnings;

my $names = 'Fred or Barney';

# ()で囲った範囲の文字列はキャプチャされ、後方参照や変数での再利用ができる
# (?: で始まる括弧では文字列はキャプチャされない
if ($names =~ m/(\w+) (?:and|or) (\w+)/) {
    say "I saw $1 and $2"; # ()でキャプチャした文字列は$1,$2...で呼び出せる
}

# Perl5.10以降では、
# (?<ラベル>で始まる括弧でキャプチャした文字列は、
# %+というハッシュに記録され、$+{ラベル}で呼び出せる
if ($names =~ m/(?<name1>\w+) (?:and|or) (?<name2>\w+)/) {
    say "I saw $+{name1} and $+{name2}";
}
名前付きキャプチャの後方参照:
#!/usr/bin/env perl
use v5.12;
use warnings;

my $names = 'Fred Flinstrone and Wilma Flinstrone';

# 名前付きキャプチャの後方参照には \g{ラベル} という記法を使う
if ($names =~ m/(?\w+) and \w+ \g{last_name}/) {
    say "I saw $+{last_name}";
}
自動マッチ変数(括弧でキャプチャしなくても自動でセットされる変数):
#!/usr/bin/env perl
use v5.12;
use warnings;

if ("Hello there, neighbor" =~ /\s\w+,/) { # 括弧でキャプチャしていない
    # &`: マッチした部分より前にあるもの
    # $&: マッチした部分
    # &': マッチした部分より後ろにあるもの
    # 自動マッチ変数3つを連結すると、元の文字列を復元できる
    say "That was ($`)($&)($')";
}
※自動マッチ変数は、次のマッチが実行されるまで値を保持する
※自動マッチ変数を使うと、プログラム全体の正規表現が少しだけ遅くなる

自動マッチ変数を一部だけ使用する/p(Perl 5.10以上):
#!/usr/bin/env perl
use v5.12;
use warnings;

if ("Hello there, neighbor" =~ /\s\w+,/p) {
    # ${^PREMATCH} : マッチした部分より前にあるもの
    # ${^MATCH} : マッチした部分
    # ${^POSTMATCH} : マッチした部分より後にあるもの
    say "That was (${^PREMATCH})(${^MATCH})(${^POSTMATCH})";
}

感想

Perl正規表現は機能が豊富で、新しい機能もどんどん追加されている、という話は聞いていたけど、確かにその通りだった。Perlでは、初心者本でここまで詳細に正規表現を解説するのか! と驚いた。

あと、名前付きキャプチャについて、「PHPでも使えないかな」と思って試してみたら、使えた:

<?php
if (preg_match('/(?<hoge>hoge)/', 'hogefuga', $matched)) {
    echo  $matched['hoge'], PHP_EOL; // hoge
}
教訓:他言語を学ぶことで、メインで使ってる言語についても、より深く学ぶことができる。