Perl:正規表現を使ったパターンマッチ

文:Nick Gibson(Builder AU) 翻訳校正:石橋啓一郎
2007-12-26 08:00:00
  • このエントリーをはてなブックマークに追加

 Perlには正規表現がネイティブサポートされており、テキスト処理には以前から非常によく使われている。この入門記事では、プログラムで正規表現を使ってテキストを検索し、置換する方法について簡単に説明していこう。

 まず、正規表現のもっとも簡単な演算であるパターンマッチから始めよう。パターンマッチ演算は、もし文字列中にそのパターンが見つかれば真を返す。次の表現を見て欲しい。

$string =~ m/text/

 この正規表現は、変数$stringに部分文字列"text"が含まれている場合にのみ真になる。これは各キャラクターをそのままマッチングさせるという、もっとも基本的な正規表現だ。これはもちろん、正規表現ができることのごく一部に過ぎない。例えば、"ext"で終わる4文字の単語を見つける必要がある場合を考えてみよう。この場合、特別な意味を持つメタ文字"."を使う。正規表現では、"."はその場所にある任意の1文字に一致する。次の正規表現を見て欲しい。

$string =~ m/.ext/

 この正規表現は、"text"や"next"などの単語と一致する。

 だが、この正規表現は完全なものではない。なぜなら、この正規表現は例えば"dextrous"や"flextime"のような"ext"を含むより長い単語にも一致してしまうからだ。アンカーを使うことによって、パターンマッチを行う位置を制約することができる。"^"という文字は文字列のはじめに一致する。このため、

$string =~ m/^.ext/

 この正規表現は"dextrous"には一致するが、"context"には一致しない。

 同じように、"$"という文字は文字列の最後に一致する。従って、

$string =~ m/.ext$/

 この正規表現は"context"には一致するが、"dextrous"には一致しない。

 もし、"ext"で終わる4文字の文字列だけに一致させたいのであれば、前述の2つを次のように組み合わせればよい。

$string =~ m/^.ext$/

 さて、次に"."の場所に任意の文字を一致させる代わりに、特定の文字の集合の1つに一致させる必要がある場合を考えてみよう。正規表現では、角括弧を使ってこれを実現している。次の正規表現を見て欲しい。

$string =~ m/^[tT]ext$/

 この正規表現は、"text"と"Text"にしか一致せず、"next"には一致しない。角括弧のペア"[]"は、その中に含まれる任意の1文字に翻訳される。これは非常に強力だ。次の例を見て欲しい。

$string =~ m/[aeiouAEIOU]/

 上の例は、$stringに母音の1つが含まれていれば真になる。

 もし角括弧の中の最初の文字が"^"であれば、これはアンカーではなくリストの否定になり、角括弧の中にあるもの以外の任意の文字に一致する。従って、前の例を$stringに子音や句読点だけが含まれている場合に真になる表現に変えるためには次のようにする。

$string =~ m/[^aeiouAEIOU]/

 角括弧の表記では、連続した数字や文字をすべて列挙する手間を省くため、文字の範囲を指定することもできる。例えば、次の正規表現は任意の小文字アルファベット1文字に一致する。

$string =~ m/[a-z]/

 これまでの例では文字列を1文字単位で扱ってきたが、多くの場合はもっと複雑なものを扱う必要がある。これを行う方法の1つが、選択一致演算を行う"|"を使うことだ。$stringに"next"か"previous"のどちらかが含まれているかどうかを調べるには、次のようにすればよい。

$string =~ m/next|previous/

 この表現とアンカーを一緒に使いたい場合には、選択肢の部分を1つにまとめる必要がある。このためには算数と同じように丸括弧を使う。前の例を"next"か"previous"のどちらかで始まる文字列だけに一致する表現にしたければ、次のようにする。

$string =~ m/^(next|previous)/

 これらの演算子はすべてアトミック演算子と呼ばれるもので、1つの文字に対応するものだ。しかし、正規表現の真の強みは、繰り返しの処理にある。それを明らかにするため、文字列が妥当な電話番号になっているかどうかを判定するという場合の例を見てみよう。まず"*"で表されるグロブ演算子を使うものから始める。コマンド行を使ったことのある人の多くは、"*"がワイルドカードとして使われているのを知っていることと思うが、Perlでも似た使い方がされており、この前に置かれている文字の任意の回数の繰り返しに一致する。従って、

$string =~ m/a*/

 この正規表現は任意の長さの"a"の繰り返しに一致する。また、次の表現は任意の長さの数字の繰り返しに一致する。

$string =~ m/[0-9]*/

 これは数字が0個の場合も含め、どんな長さの数にも一致してしまうため、求めているものとは違っている。その代わりに、前に置かれている文字の1回以上の繰り返しを表す"+"演算子を使うこともできるが、桁数が多すぎたり少なすぎたりする場合があるという問題には対応できない。ここでは、繰り返しの数を正確に指定したい。これは、波括弧"{}"を使って次のように指定できる。この場合、繰り返しの数は7回になる。

$string =~ m/^[0-9]{7}$/

 求めているものにだんだん近づいては来ているが、これは単に7桁の数字を含む文字列に一致するというだけだ。中括弧には、さらにいくつかの繰り返しの指定をより強力なものにする機能がある。例えば、繰り返しの回数の範囲を指定してパターンマッチを行うことができる。

$string =~ m/[0-9]{6,8}/

 この例は6桁から8桁の数字に一致するものだが、これを"{6,}"に変えると6回以上の繰り返しに一致し、"{,8}"に変えると8回以下の繰り返しに一致するようになる。

 電話番号を別の見方で見てみよう。これまでのところこれは正しく動いているが、少し制約が多すぎる。ユーザーからの入力を扱う際には、ユーザーは簡単なことを多くの異なる形で行おうとするということを考慮に入れる必要がある。

 電話の入力に使われる、いくつかの一般的な形式を考慮に入れておくことは、いいアイデアだろう。例えば"2391720"という簡単な数字を例に取ると、これは"239-1720"や"239 1720"という形で入力されることもあるだろう。角括弧を使って"-"か" "のどちらかに一致させることができるが、今回は数字を分ける記号が1つも入っていない場合にも対応する必要がある。ここでは、前に置かれている文字が出現するかもしれないし、出現しないかもしれないということを示す"?"演算子を使う。次の正規表現は、上記の3つの形式すべてに一致する。

$string =~ m/[0-9]{3}[- ]?[0-9]{4}/

 同じように、エリアコード(市外局番)についても扱えるようにしよう。オーストラリアでは、エリアコードは2桁であるため、次のように変更した。

$string =~ m/([0-9]{2}[- ]?)?[0-9]{3}[- ]?[0-9]{4}/

 この正規表現は、"02 114 7682"というような数字に一致する一方、正規表現のエリアコードを表す部分を丸括弧で囲い、あってもなくても一致するようにしたことから、前の正規表現の例に一致するすべてのものにも一致する。他にも、例えばエリアコードを"("と")"で囲う形式に対応するなど改良の余地はあるが、選択肢を多くすればするほど正規表現は複雑になることはわかっただろうと思う。この問題は読者に任せよう。

 次回は、置換や変換、そしてどのように正規表現を組み込んだPerlプログラムを作るかといったことを含む、正規表現のより深い部分に踏み込んでいく予定だ。

この記事は海外CNET Networks発のニュースをシーネットネットワークスジャパン編集部 が日本向けに編集したものです。海外CNET Networksの記事へ

  • 新着記事
  • 特集
  • ブログ
このサイトでは、利用状況の把握や広告配信などのために、Cookieなどを使用してアクセスデータを取得・利用しています。 これ以降ページを遷移した場合、Cookieなどの設定や使用に同意したことになります。
Cookieなどの設定や使用の詳細、オプトアウトについては詳細をご覧ください。
[ 閉じる ]