[Perlトップページ]

正規表現

正規表現 - / / -

正規表現とは耳慣れない言葉ですが、 特定の文字列がある文字列に存在するかどうかを 調べるためのものと考えてください。 存在する=マッチすると呼ばれますが、 単にマッチするかどうかを調べたり、マッチする場合に 別の文字列で置換したりと様々なことができます。

正規表現の基本は/ /でくくることです。 たとえば/a/という正規表現を用いると

'a'
'yamada'
'bbbbbbbba'

という文字列にマッチします。つまりaという 文字列(ここでは文字ですが)を含む文字列にはすべてマッチします。

演習6-1

下記のスクリプトをkadai6-1.plとして書き、正しく実行されるか確認せよ。

#!/usr/bin/perl

@array = ('panda', 'sandy', 'andrology', 'And', 'Can do?');

foreach (@array){
    if ($_ =~ /and/) {
        print "$_ にマッチします\n";
    } else {
        print "$_ にマッチしません\n";
    }
}
-------------------------------
(上記の記述は下記と同じ)

for ($i = 0; $i < @array; $i++){
    if ($array[$i] =~ /and/) {
        print "$array[$i] にマッチします\n";
    } else {
        print "$array[$i] にマッチしません\n";
    }
}
(実行結果)

panda にマッチします
sandy にマッチします
andrology にマッチします
And にマッチしません
Can do? にマッチしません

つぎに少し機能を付け加えます。「特別な意味を持った」という意味の メタ文字を使います。

メタ文字 マッチングの条件 用例 マッチング例
^ 文字列の先頭にあればマッチする /^and/ ando
anddddddd
$ 文字列のおわりにあればマッチする /and$/ land
dreamland
\b 単語の境界にあればマッチする /man\b/ man
woman
\B 単語の境界以外にあればマッチする /\Bサッカー\B/ 県サッカー協会
情報大サッカー部

演習6-2

下記のスクリプトをkadai6-2.plとして書き、正しく実行されるか確認せよ。

#!/usr/bin/perl

@array = ('pand', 'sandy', 'andrology');

print "文字列の先頭へのマッチング\n";

foreach (@array){
    if ($_ =~ /^and/) {
        print "$_ にマッチします\n";
    } else {
        print "$_ にマッチしません\n";
    }
}

print "\n文字列のおわりへのマッチング\n";

foreach (@array){
    if ($_ =~ /and$/) {
        print "$_ にマッチします\n";
    } else {
        print "$_ にマッチしません\n";
    }
}
(実行結果)

文字列の先頭へのマッチング
pand にマッチしません
sandy にマッチしません
andrology にマッチします

文字列のおわりへのマッチング
pand にマッチします
sandy にマッチしません
andrology にマッチしません

次の演習6-3では、マッチングのオプションである修飾子を使います。

修飾子 意味
g マッチするものすべてを見つける
i 大文字・小文字の区別をしない
m 文字列を複数行として扱う
s 文字列を単一行として扱う(文字列内の改行を無視)

演習6-3

下記の英文から、大文字、小文字に関係なく boxがつく単語を抽出したい。つまり、boxboxesboxingも抽出したい。下記のスクリプトを kadai6-3.plとして書き、正しく実行されるか確認せよ。ちなみに、 $&は「マッチした範囲に対応する変数」であり、 これを利用してマッチングの結果を確認している。

対象とする英文

I like to collect boxes, and I have a lot of boxes. <-改行
Boxes in my room are very attractive. <-改行
I also like watching and playing boxing. <-改行
Boxing is very exciting.
#!/usr/bin/perl

$sentence =
'I like to collect boxes, and I have a lot of boxes.
Boxes in my room are very attractive.
I also like watching and playing boxing.
Boxing is very exciting.';

print "メタ文字^, 修飾子i,g \n";
while ($sentence =~ /^box/ig){
    print "$& \n";
}

print "メタ文字^, 修飾子i,s,g \n";
while ($sentence =~ /^box/isg){
    print "$& \n";
}

print "メタ文字^, 修飾子i,m,g \n";
while ($sentence =~ /^box/img){
    print "$& \n";
}

print "メタ文字\\b, 修飾子i,g, \n";
while ($sentence =~ /\bbox/ig){
    print "$& \n";
}

print "メタ文字なし, 修飾子i,g\n";
while ($sentence =~ /box/ig){
    print "$& \n";
}
(実行結果)

メタ文字^, 修飾子i,g
メタ文字^, 修飾子i,s,g
メタ文字^, 修飾子i,m,g
Box
Box
メタ文字\b, 修飾子i,g
box
box
Box
box
Box
メタ文字なし, 修飾子i,g
box
box
Box
box
Box

演習6-3では、マッチする箇所は見つけられたものの、 boxBoxしか抽出できておらず、boxesboxingのような単語は抽出できておりません。 そのためには、下記のメタ文字を利用することになります。

メタ文字 マッチングの条件 用例 マッチング例
. 任意の1文字が存在すればマッチ /fa./ fax
fantastic
? 直前のものがあってもなくてもマッチ /colou?r/ color
colour
* 直前のものが0回以上繰り返すとマッチ /yahoo*/ yaho
yahooooo
+ 直前のものが1回以上繰り返すとマッチ /yahoo+/ yahoo
yahooooo
{m} 直前のものがm回繰り返すとマッチ /アタ{4}/ アタタタタ
{m,} 直前のものがm回以上繰り返すとマッチ /(アタ){2,}/ アタアタアタ
{m, n} 直前のものがm回以上n回以下繰り返すとマッチ /トロ{3,4}/ トロロロ
トロロロロ
メタ文字 マッチングの条件 用例 マッチング例
| 選択 /go(es|ne|ing)/ goes
gone
going
[0-9] 0-9までの数字にマッチ /data[0123456789]/ /data[0-9]/ /data\d/ ※3つとも同じ意味 data1
data8
[a-zA-Z0-9_] 英数字と _ にマッチ /data[a-zA-Z0-9_]/ /data\w/ ※2つとも同じ意味 data1
data8
[^ ] 否定 /data[^0-9]/ /data[^\d]/ /data\D/ ※3つとも同じ意味 dataa
data_

演習6-4

演習6-3に引き続き、下記の英文から大文字、小文字に関係なく boxがつく単語を抽出したい。つまり、boxboxesboxingも抽出したい。下記のスクリプトを kadai6-4.plとして書き、正しく実行されるか確認せよ。

I like to collect boxes, and I have a lot of boxes. <-改行
Boxes in my room are very attractive. <-改行
I also like watching and playing boxing. <-改行
Boxing is very exciting.
#!/usr/bin/perl

$sentence =
'I like to collect boxes, and I have a lot of boxes.
Boxes in my room are very attractive.
I also like watching and playing boxing.
Boxing is very exciting.';

print "メタ文字なし, 修飾子i,g\n";
while ($sentence =~ /box/ig){
    print "$& \n";
}

print "メタ文字., 修飾子i,g\n";
while ($sentence =~ /box./ig){
    print "$& \n";
}

print "メタ文字\\w, 修飾子i,g\n";
while ($sentence =~ /box\w/ig){
    print "$& \n";

}

print "メタ文字(\\w)+, 修飾子i,g\n";
while ($sentence =~ /box(\w)+/ig){
    print "$& \n";
}
(実行結果) メタ文字なし, 修飾子i,g box box Box box Box メタ文字., 修飾子i,g boxe boxe Boxe boxi Boxi メタ文字\w, 修飾子i,g boxe boxe Boxe boxi Boxi メタ文字(\w)+, 修飾子i,g boxes boxes Boxes boxing Boxing

演習6-5

下記の数字が入っている配列から、3桁以上の数字を抽出したい。 どのような正規表現なら可能か?下記のスクリプトのうち、 **********で隠された部分を補いkadai6-5.plとして書き、 正しく実行されるか確認せよ。

#!/usr/bin/perl

@array = (92, 101, 8, 2228, 9);

foreach (@array){
    if ($_ =~ /*****************/) {
        print "$_ は3桁以上の数字\n";
    } else {
        print "$_ は3桁以上の数字ではない\n";
    }
}
(実行結果)

92 は3桁以上の数字ではない
101 は3桁以上の数字
8 は3桁以上の数字ではない
2228 は3桁以上の数字
9 は3桁以上の数字ではない

演習6-6

下記のスクリプトは、数字の並びからIPアドレスかどうかを判断し、 さらにフロンティア棟内のIPかどうか判断するものである。 このスクリプトをkadai6-6.plとして書き、正しく実行されるか確認せよ。

#!/usr/bin/perl

@ip = ('202.26.149.11', '1.2.3', '202.26.153.180', '127.0.0.1', '2.2.2.2.2');

foreach (@ip){
    if ($_ =~ /^(\d+).(\d+).(\d+).(\d+)$/){
        if ($1 == 202 && $2 == 26 && $3 == 153){
             print "IPアドレス $_ は、フロンティア棟内のものです。\n";
        } else {
             print "IPアドレス $_ は、フロンティア棟内のものではありません。\n";
        }
    }
    else {
        print "この数字 $_ はIPアドレスではありません。\n";
    }
}
(実行結果)

IPアドレス 202.26.149.11 は、フロンティア棟内のものではありません。
この数字 1.2.3 はIPアドレスではありません。
IPアドレス 202.26.153.180 は、フロンティア棟内のものです。
IPアドレス 127.0.0.1 は、フロンティア棟内のものではありません。
この数字 2.2.2.2.2 はIPアドレスではありません。

置換 - s/ / / -

置換については「変数と文字列」の 中でも紹介しましたが、下記の方法で、 ある文字列の中から特定の文字列を別の文字列に置き換えてくれます。

文字列全[ =~ s/置換前の文字列/置換後の文字列/;

ここでは、様々なメタ文字や修飾子を利用していろいろな 演習問題に取り組んでもらいます。

演習6-7

下記のスクリプトをkadai6-7.plとして書き、正しく実行されるか確認せよ。

#!/usr/bin/perl

$str = "He and I like cake and candy\n";
$str =~ s/and/AND/;
print $str;

$str = "He and I like cake and candy\n";
$str =~ s/and/AND/g;
print $str;

$str = "He and I like cake and candy\n";
$str =~ s/\band\b/AND/g;
print $str;
(実行結果)

He AND I like cake and candy
He AND I like cake AND cANDy
He AND I like cake AND candy

演習6-8

"research"という単語を"reserch"と間違う 癖のある人の文章を修正したい。下記のスクリプトをkadai6-8.plとして書き、正しく実行されるか確認せよ。

#!/usr/bin/perl

$str = 'We have done lots of reserches.
This year reserch list is below.';

print $str, "\n\n";

$str =~ s/reserch/research/g;

print $str, "\n";
(実行結果)

We have done lots of reserches.
This year reserch list is below.

We have done lots of researches.
This year research list is below.

演習6-9

演習6-8に関連して、"research"という単語を "reserch", "reseach", "resarch"の 3通りに間違う癖のある人の文章を修正したい。下記のスクリプトのうち******で隠された部分を補ってkadai6-9.plとして書き、正しく実行されるか確認せよ。

#!/usr/bin/perl

$str = 'We have done lots of reserches.
This year resarch list is below.
I hope to obtain a big reseach fund.';

print $str, "\n\n";

$str =~ s/*******/*******/g;

print $str, "\n";
(実行結果)

We have done lots of reserches.
This year resarch list is below.
I hope to obtain a big reseach fund.

We have done lots of researches.
This year research list is below.
I hope to obtain a big research fund.

演習6-10

演習6-9で作成したkadai6-9.plが、大文字で始まる "Resarch"という間違いにも対応するようにしたい。 下記のスクリプトのうち******で隠された部分を補って kadai6-10.plとして書き、正しく実行されるか確認せよ。

#!/usr/bin/perl

$str = 'We have done lots of reserches.
This year resarch list is below.
I hope to obtain a big reseach fund.
Resarch is interesting';

print $str, "\n\n";

$str =~ s/*******/*******/g;

print $str, "\n";
(実行結果)

We have done lots of reserches.
This year resarch list is below.
I hope to obtain a big reseach fund.
Resarch is interesting.

We have done lots of researches.
This year research list is below.
I hope to obtain a big research fund.
Research is interesting.

演習6-11

今度は、スペースを2つ以上続けて入力した間違いを修正したい。 下記のスクリプトのうち******で隠された部分を補って kadai6-11.plとして書き、正しく実行されるか確認せよ。

#!/usr/bin/perl

$str = 'We   have done  lots of   reserches.';
print $str, "\n";

$str =~ s/*******/*******/g;
print $str, "\n";
(実行結果)

We   have done  lots of   reserches.
We have done lots of reserches.

演習6-12

情報大に関連する電話番号のリストがあるが、 "236-2215"や"043-236-2601"のように 市外局番の付け方がばらばらであり、全て"043-"で始まる 記述に修正したい。下記のスクリプトのうち******で隠された部分を補って kadai6-12.plとして書き、正しく実行されるか確認せよ。

#!/usr/bin/perl

@list = ('236-2215', '043-236-2601', '236-2622');

foreach (@list){
    print $_, "---> ";
    $_ =~ s/*********/*********/;
    print $_, "\n";
}
(実行結果)

236-2215---> 043-236-2215
043-236-2601---> 043-236-2601
236-2622---> 043-236-2622

演習6-13

文字列中の" "で囲まれた文字列を抽出したい。 下記のスクリプトのうち******で隠された部分を補って kadai6-13.plとして書き、正しく実行されるか確認せよ。

#!/usr/bin/perl

$str = 'She said "Why not?", but he just said "Sorry."';

while ($str =~ /************/g){
    print "$& \n";
}
(実行結果)

"Why not?"
"Sorry."

演習6-14

文字列中のHTMLタグを除去したい。下記のスクリプトのうち ******で隠された部分を補ってkadai6-14.plとして書き、 正しく実行されるか確認せよ。

#!/usr/bin/perl

$str = '<li>今月の<b>掃除当番</b>のお知らせ</li>';

$str =~ s/********/********/g;
print "$str \n";
(実行結果)

今月の掃除当番のお知らせ

[Perl講座] [須崎純一トップページ]
須崎純一 京都大学大学 工学研究科都市環境工学専攻 環境情報学講座