Pattern Match

last-modified: 12th/June/'01;
since: 1st/June/2001;

Perl は文字列処理に適した言語です。前節で正規表現を紹介したので、本節では文字列を検索、置換、変換するスクリプトを紹介します。

パターンマッチ

文字列 string に正規表現によるパターン pattern がマッチするかどうか調べるには、次のように記述します;

string =~ /pattern/

input.pl で紹介しました。本節では改めて紹介します。

次のスクリプトは、正規表現と任意の文字列を入力すると、どの部分にパターンマッチしたかを出力するものです。

正規表現の練習にご利用ください。

regexp.pl>>

 1:
 2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
10:
11:
12:
13:
14:
15:
16:
17:
#!/usr/bin/perl
#上の行では、 Perl のパスを記述してください。
while(1) {
  print "Regular Expression (x to exit): ";
  chomp($pattern = <STDIN>);
  last if ($pattern eq 'x');
  while(1) {
    print "Matched line (x to exit):";
    chomp($line = <STDIN>);
    last if ($line eq 'x');
    if ($line =~ /$pattern/) {
      print "Matched string is \"$&\"\n";
    } else {
      print "failed\n";
    }
  }
}

[説明]

実行例>>

% perl regexp.pl
Regular Expression (x to exit): 時.*分
Matched line (x to exit):今日は9時15分から食事の約束が入っている。
Matched string is "時15分"
Matched line (x to exit):明日は11時30分からゼミがある。
Matched string is "時30分"
Matched line (x to exit):x
% 

区切り文字の変更

正規表現中では、区切り文字もエスケープする必要があります。「 http://www. 」にマッチさせるには、次のように記述する必要があります。

$a =~ /http:\/\/www\./

エスケープ回数を減らすために、正規表現を区切る記号を変更することができます。英数字とアンダースコア( _ )以外の任意の記号に変えられます。

$a =~ m#正規表現#
$a =~ m{正規表現}
$a =~ m!正規表現!
$a =~ m+正規表現+
$a =~ m*正規表現*

但し、区切り文字に採用した記号はメタ文字になりますから、正規表現中ではエスケープする必要があります。次の例は「 begin{document 」を含むかどうか判定します。

$a =~ m{begin\{document}

/正規表現/ は、 m/正規表現/ の省略形です。区切り子がスラッシュ / に限り、 m を省略できます。

オプション

パターンマッチにはオプションをつけることができます。ここでは三つだけ紹介します。

/正規表現/m
/正規表現/s
/正規表現/i

上から順番に、「置換対象文字列の改行文字を改行として扱う」、「置換対照の文字列の改行文字を単なる文字として扱う」、「大文字小文字の無視」です。

[パターンマッチのオプションの利用例]
$a = abc def\nghi jkl例文改行文字 \n が含まれる。
$a =~ /def$/行末が def
$a =~ /def$/m
$a =~ /a.*l/al の間に任意の文字列。
$a =~ /a.*l/s
$a =~ /ABC/文字列 ABC
$a =~ /ABC/i
$a =~ /A*.L/mi

置換

m/正規表現/ では文字列を検索していました。次に、パターンにマッチする文字列を置換する書式を紹介します。

$variable =~ s/pattern/replace/

文字列 $variable から pattern に一致する部分を探し出し、 replace に置換します。

変数からパターンを探して置換した結果が、元の変数に代入されなおします。戻り値は、置換回数です。

replace.pl>>

while(1) {
  print "ご自由にどうぞ!:";
  chomp ($line = <STDIN>);
  last if $line eq '';
  $line =~ s/だ|です/じゃない/;
  $line =~ s/私/あなた/;
  print "-> $line\n";
}

実行例>>

% perl repl.pl
ご自由にどうぞ!:私は日本人です。
-> あなたは日本人じゃない。
ご自由にどうぞ!:私は男だ。
-> あなたは男じゃない。
ご自由にどうぞ!:あなたはアメリカ人だ。
-> あなたはアメリカ人じゃない。
ご自由にどうぞ!:私は日本人で、私は男です。
-> あなたは日本人で、私は男じゃない。
ご自由にどうぞ!:
% 

最後の例に注目してください。マッチする文字列が複数回登場すると、最初にマッチしたものしか置換されません。これを全て置換するには、オプションをつけます。

オプション

置換のオプションはいくつか用意されていますが、ここでは四つだけ紹介します。

s/パターン/置換文字列/g
s/パターン/置換文字列/m
s/パターン/置換文字列/s
s/パターン/置換文字列/i

上から順番に、「マッチするもの全ての置換」、「置換対象文字列の改行文字を改行として扱う置換」、「置換対照の文字列の改行文字を単なる文字として扱う置換」、「大文字小文字の無視」です。

[文字列置換のオプションの利用例]
$a = abc def\nabc jkl改行文字 \n が含まれる。
$a =~ s/abc/xyz/xyz def\nabc jkl
$a =~ s/abc/xyz/gxyz def\nxyz jkl
$a =~ s/def$/xyz/mabc xyz\babc jkl
$a =~ s/a.*l/xyz/sxyz
$a =~ s/ABC/xyz/ixyz def\nabc jkl
$a =~ s/ABC/xyz/gixyz def\nxyz jkl

実用的な例としては、文章の表記ゆれの統一や、データの整形が挙げられます。

[文字列置換の利用例]
文末の「だ。」、「である。」を「です。」に変換 s/だ|である。/です。/g
Perl, perl, PERL を全て Perl に変換。 s/perl/Perl/ig
0120-444-444 を 0120(444)444 に変換。 s/(\d{4})\-(\d{3})\-(\d{4})/$1\($2\)$3/g

\d は半角数字を表す文字集合で、 [0-9] と等価です。 \d{4} は半角数字 4 回の繰り返しです。 2 回以上 4 回以下の繰り返しなら \d{2,4} です。電話番号は一般に \d{2,4}-\d{3,4}-\d{4} で表現できます。

$1, $2, $3,... は、パターンマッチしたグループが順に代入されている特殊変数で、後方参照変数と呼びます。この変数を利用した例を紹介しておきます。

[後方参照変数の利用例]
s/(菅井)((株)|株式会社)/$2$1/g菅井株式会社菅井(株) -> (株)菅井
s/(\d+)円/\\$1\-/g500円15000円 など -> \500-, \15000- など
s/<(br|hr|img|link|input|col|base|meta|area|param)(.*?)>/<$1$2 \/>/g空要素の終端を ">" -> " />" に置換
s/<(\/)?([\w]+)/<$1\L$2/g要素名を小文字にする。 \L\E までを小文字にするが、今は指定されていないので、 $2 ([\w]+) 全てを小文字にする。\w は英数字で [0-9A-Za-z_] と等価。

\- を表現するためにはエスケープする必要があり、それぞれ \\, \- と表現しました。

区切り文字の変更

置換でも区切り文字は変更できます。

$a =~ s!パターン!置換文字列!
$a =~ s#パターン#置換文字列#
$a =~ s{パターン}{置換文字列}

変換

パターンマッチ m/.../、置換 s/.../.../ を紹介しました。最後に、変換 tr/.../.../ を紹介します。

置換では、文字列を別の文字列に置換していました。変換では、文字を別の文字に変換します。

$variable =~ tr/string/replace/

変数から string に含まれる全ての文字が、 replace の中から順番が対応する文字に変換されます。

transfer.pl>>

$a = abcdefg;
print "$a ";
$a =~ tr/d-g/1-4/;
print "-> $a\n";

実行例>>

% perl transfer.pl
abcdefg -> abc1234
%

tr/文字集合/変換文字集合/ において、「文字集合」と「変換文字集合」の個数が対応しない場合は、「変換文字集合の最後の文字」が繰り返されて帳尻が合います。従って、次の二行は同じことです;

$a =~ tr/aogrm/kws/
$a =~ tr/aogrm/kwsss/

オプション

文字変換にもオプションがあります。

tr/文字集合/変換文字集合/d
tr/文字集合/変換文字集合/c
tr/文字集合/変換文字集合/s

上から順番に、「文字集合中の文字で、変換文字集合に無い文字は消す」、「文字集合の補集合」、「変換後に同じ文字が重なったときに一文字に縮める」と云う意味です。

[文字変換のオプションの利用例]
$a = abcdef
$a =~ tr/abc/xyz/xyzdef
$a =~ tr/abcd/xy/xyyyef
$a =~ tr/abc/b/dbdef
$a =~ tr/abc/z/cabczzz
$a =~ tr/ac/b/sbdef
Copyright: SUGAI, Manabu. Since: 2001