第7章「正規表現の基本」

ある部分文字列を検索(または置換など)したい場合に、探したい文字列をパターンによって指定できる。その指定するパターンのことを正規表現と呼ぶ。
Perlでは、正規表現

/hoge/

のように、スラッシュで囲んで表現する。で、このパターンを演算子=~と組み合わせて

$str =~ /hoge/

として、if文などの条件文として書いてやると、マッチするかどうか調べられる。他にも、split関数のように、パターンを引数に要求するものもある。

まとめ

メタ文字のまとめ

メタ文字 意味
^ 文字列の先頭。文字クラスの中で使った場合は、直後に指定した文字以外。
$ 文字列の末尾
. 任意の一文字
\d 半角数字一文字
\w 半角英数一文字
? 直前の文字の高々1回の繰り返し
* 直前の文字の0回以上の繰り返し
+ 直前の文字の1回以上の繰り返し
| または。カッコとともに用いることもある。
以下は同じ意味

  • [0123456789]と[0-9]と\d
  • [0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_]と[0-9A-Za-z_]と\w
  • [^0-9]と[^\d]と\D
  • ?と{0,1}({1, 4}で1回以上4回以下の繰り返しであることを指定できる)
  • *と{0,}(上限は指定しなくてもいい)
  • +と{1,}
正規表現の例

正規表現 意味 マッチする例 マッチしない例
/yes/ 'yes' 'yes', 'yesterday', 'eyes' 'Yes', 'y e s', 'yeS'
/^yes/ 'yes'から始まる 'yes', 'yesterday, 'yes no' 'Yes', 'eyes', 'no yes'
/yes$/ 'yes'で終わる 'yes', 'eyes', ' yes' 'Yes', 'yesterday', 'yes, it is.'
/ca./ 'ca'で始まる3文字 'car', 'cap', 'this is cat.' 'CAT', 'ca'
/point\d/ 'point'のあとに数字一文字 'point0', 'point1' 'points', 'Point1'
/point\w/ 'point'のあとに、英数またはアンダースコア 'points', 'point1', 'point_', 'pointing' 'point', 'point?'
/point[^\d]/ 'point'のあとに数字以外の一文字 'You got 3 points.', 'point x' 'point0', 'point1'
/colou?r/ 'color'または'colour' 'color', 'colour', 'colorful' 'Colour', 'c o l o r'
/go*d/ 'g'、0回以上の'o'、'd'が連続したもの 'gd', 'god', 'good', 'goood' 'g o d', 'g00d', 'goooo'
/go+d/ 'g'、1回以上の'o'、'd'が連続したもの 'god', 'good', 'gooooood' 'gd', 'g o d', 'g00d', 'goooo'
/This is (red|green|blue)/ 'This is 'のあとに'red'または'green'または'blue' 'This is red', 'This is green', 'This is blue' 'This is Red'

マッチした文字列を得る変数 $&

演算子=~で、マッチするかどうかを調べたあと、マッチしていればそのマッチした部分が変数$&を束縛するらしい。こんな風に使える。

my @str = ('Yes', 'yes', 'yes no', 'no yes', 'myes', 'yesterday', 'y e s', 'yes, it is.', ' yes');
foreach (@str)
{
  print $_, ':';
  if ($_ =~ /^yes/)
  {
    print "$& --- Match!\n";
  }
  else
  {
    print 'No match!', "\n";
  }
}

http://ideone.com/v5dP5

マッチした文字列を置き換える s///

twitterで、ツイートの訂正のつもりでこれ書いている人いるね。これも演算子=~と組み合わせて使う。例えば、

my $str = 'This is a cat. That is a cat, too.';
$str =~ s/cat/dog/;
print $str;

ってやると、はじめに見つけた /cat/ にマッチする部分をdogに置換できる。さらに、

my $str = 'This is a cat. That is a cat, too.';
$str =~ s/cat/dog/g;
print $str;

ってやると、すべての /cat/ にマッチする部分をdogに置換できる。http://ideone.com/CDf09
しかし、=~は演算子だと思うけど、s///は演算子...なのかな?

メタ文字.は改行にマッチしない

任意の1文字にマッチするメタ文字.を既に学んだが、実は改行はこれにマッチしない。改行文字をマッチさせたければ、修飾子/sというのを使うと良い。

# メタ文字.は改行文字にマッチしない
if ("Hello\n" =~ /Hello./)
{
  print '"Hello" matches /Hello./', "\n";
}
else
{
  print '"Hello" does not matches /Hello./', "\n";
}

# 修飾子/sをつければ、メタ文字.は改行文字にマッチする
if ("Hello\n" =~ /Hello./s)
{
  print '"Hello" matches /Hello./s', "\n";
}
else
{
  print '"Hello" does not matches /Hello./s', "\n";
}

http://ideone.com/3y4pR

メタ文字$について

メタ文字$は文字列の終わりにマッチするけど、文字列の終わりが改行文字だったときには改行の直前にマッチする。

# メタ文字$は文字列の終わりか、改行の直前にマッチする
if ("Hello\n" =~ /Hello$/)
{
  print "$& --- Match\n";
}
else
{
  print "no match\n";
}
 
# 改行が複数ある場合はどうなるのか?
if ("Hello1\nHello2\n" =~ /Hello\d$/)
{
  print "$& --- Match\n";
}
else
{
  print "no match\n";
}
 
# 修飾子/mをつけると、1つの文字列があたかも改行で区切られた複数の文字列のように振る舞う
if ("Hello1\nHello2\nHello3\n" =~ /Hello\d$/m)
{
  print "$& --- Match\n";
}
else
{
  print "no match\n";
}
 
# さらに修飾子/gを付加し、/mgとすると、繰り返し調べられる
while ("Hello1\nHello2\n" =~ /Hello\d$/mg)
{
  print "$& --- Match\n";
}

http://ideone.com/cE9WZ

正規表現オブジェクト?

正規表現を表したスラッシュで囲まれた値は、正規表現のオブジェクトをリテラルで書いているように思えて仕方ない。これってどんなオブジェクトなんだろう?どんな性質あんだろう?オブジェクト指向が頭に染み付いているので、どうしても「どんなオブジェクト?」が気になってしまう。このオブジェクトは変数に入れたり、普通にスカラーとして扱えるのかな?