Perl/正規表現
Perlは強力な 正規表現 をサポートしています。正規表現とは、大まかにいうと、検索の機能を高度化しやすくしたものです。Perl以外のJavaやJavaSciptやPHPなども正規表現をサポートしていますが、Perlは古くから正規表現を本格的にサポートしています。 また、Perlの拡張正規表現は、Perl Compatible Regular Expressions( PCRE ) としてPerlの外でも使うことができるため、正規表現のディファクトスタンダードの1つとなっています。
パターンマッチング
[編集]=~
[編集]二項演算子 =~
は、左辺のスカラー式を右辺のパターンマッチに拘束します。
正規表現に関する操作では、デフォルトで $_
という文字列を検索したり変更したりします。
この演算子は、そのような操作を他の文字列に対して行うようにします。
右辺は、検索パターン (//
)、置換 (s///
)、または変換 (tr///
) です。
左辺は、デフォルトの $_
の代わりに検索、置換、または変換されるはずのものです。
スカラーコンテキストで使用する場合、返り値は通常操作の成功を表します。
リストコンテキストでの動作は、特定の演算子に依存します。
- 検索
if ("Wikibooks" =~ /book/) { print "Match!"; } else { print "Not match."; }
- 実行結果
Match!
- 書式
$検索対象の変数 =~ /検索したい文字列/
- 検索したい文字列を、変数が内部に含んでいるかどうかを調べる際に、
=~
および/RE/
を使います。上記のコードは真偽を返すので、主に条件分岐を行う際に用いられます。
!~
[編集]!~
は、=~
の論理反転バージョンです。
- コード例
if ("Wikibooks" !~ /books/) { print "Not match."; } else { print "Match!"; }
- 実行結果
Match!
/.../
内ではダブルクォーテーション ("..."
) と同じく、変数やエスケープシーケンスが評価されます。
- コード例
$bar = "books"; "Wikibooks" =~ /$bar/ # マッチする。
置換
[編集]=~
演算子を使用すると、右辺に s///
を取ることで左辺の文字列を置換することができます。
- コード例
my $string = "Hello, world!"; $string =~ s/world/Perl/; # "world"を"Perl"に置換 print $string; # 出力は "Hello, Perl!"
上記の例では、$string
内の "world" を "Perl" に置換しています。
変換
[編集]=~
演算子を使用すると、右辺に tr///
を取ることで左辺の文字列を変換することができます。
- コード例
my $string = "hello world"; $string =~ tr/a-z/A-Z/; # アルファベットを大文字に変換 print $string; # 出力は "HELLO WORLD"
この例では、$string
内のアルファベットを小文字から大文字に変換しています。
パターンの区切り文字
[編集]m
を前置すると正規表現を囲う記号にスラッシュ以外を用いることができます。
[ ]
,( )
,< >
,{ }
などの括弧は開き括弧と閉じ括弧が対応するように用います。
$foo =~ m/bar/; $foo =~ m#bar#; $foo =~ m@bar@; $foo =~ m!bar!; $foo =~ m{bar}; $foo =~ m(bar);
囲み記号にシングルクォーテーションを用いると、変数やエスケープシーケンスが評価されるのを防ぐことができます。
$foo = "books"; "Wikibooks" =~ m/$foo/; # マッチする "Wikibooks" =~ m'$foo'; # マッチしない
正規表現における文字クラスの構文と使用方法
[編集]文字クラスは、文字の集合を表現し、その集合の中の1文字にマッチする方法です。 重要なのは、文字クラスのマッチングがソース文字列のちょうど1文字を消費するということです(ソース文字列とは、正規表現がマッチされる文字列のことです)。
文字クラス
[編集]Perlの正規表現には、ドット、バックスラッシュ・シーケンス、角括弧で囲まれた文字クラスの3種類の文字クラスがあります。
しかし、「文字クラス」という用語は、しばしば角括弧で囲まれた形式だけを意味するものとして使われることがあるので、文脈によりどちらを表しているのか注意が必要です。
ドット
[編集]ドット .
は、デフォルトでは、改行を除く全ての1文字にマッチします。
- コード例
if ("dog cat" =~ /..g/) { print "Match!"; } else { print "Not match."; }
- 実行結果
Match!
- 例えば、「..g」は文字列の末尾が "g" である3文字の単語(他の2文字目は任意)にマッチします。したがって、"dog" はこの条件を満たすのでマッチします。
- しかし、ドットを1つ追加した場合、マッチしなくなります。なぜなら、"g" の前には2文字しかないためです。
- コード例
if ("dog cat" =~ /...g/) { print "Match!"; } else { print "Not match."; }
- 実行結果
Not Match.
- dogの「g」の前には1文字以上の文字があるので、ドットが1つでもマッチします。
- コード例
if ("dog cat" =~ /.g/) { print "Match!"; } else { print "Not match."; }
- 実行結果
Match!
メタキャラクター
[編集]正規表現において特殊な意味を持つ以下の文字をメタキャラクターと呼びます。
+ * ? . ( ) [ ] { } | \ $ ^
これらの文字自身を表すには \+
, \*
のようにバックスラッシュでエスケープします。
アンカー
[編集]「アンカー」とは長さを持たない正規表現です。
代表的なものに、文字列先頭にマッチする ^
、文字列末尾にマッチする $
があります。
- 書式
"Wikibooks" =~ /^Wiki/; # マッチする "Wikibooks" =~ /books$/; # マッチする "Wikibooks" =~ /Wiki$/; # マッチしない
- コード例
if ("Wikibooks" =~ /^Wiki/) { print "Match!"; } else { print "Not match."; }
- 実行結果
Match!
文字列「Wiki」は検索対象の先頭にあるのでマッチします。
if ("Wikibooks" =~ /^books/) { print "Match!"; } else { print "Not match."; }
- 実行結果
Not Match.
文字列「books」は検索対象に含まれていますが、先頭にはないのでマッチしません。
他に、単語の境界(正確には、単語の先頭あるいは末尾)にマッチする \b
、それ以外の部分にマッチする \B
があります。つまり、その位置に半角スペースまたは単語の先頭あるいは終わりがある場合にマッチします。
- 書式
"dog cat" =~ /a\b/; # マッチしない "dog cat" =~ /g\b/; # マッチする
- コード例
if ("dog cat" =~ /g\b/) { print "Match!"; } else { print "Not match."; }
- 実行結果
Match!
dogのgの後ろに半角スペースがあるので、結果はマッチです。
- コード例
if ("dog cat" =~ /a\b/) { print "Match!"; } else { print "Not match."; }
- 実行結果
Not Match.
catのなかに「a」がありますが、位置が単語の境界ではないので、マッチしません。
バックスラッシュ・シーケンス
[編集]バックスラッシュ・シーケンスとは、最初の1文字がバックスラッシュである文字の並びのことです。Perlはこのような多くのシーケンスに特別な意味を持たせており、そのうちのいくつかは文字クラスになっています。つまり,その文字がシーケンスで定義された特定の文字集合に属していれば,それぞれ1つの文字にマッチします。
記号 | 意味 |
---|---|
\d
|
10進数文字にマッチします。 |
\D
|
10進でない桁の文字にマッチします。 |
\w
|
単語文字にマッチします。 |
\W
|
単語以外の文字にマッチします。 |
\s
|
空白文字にマッチします。 |
\S
|
非空白文字にマッチします。 |
\h
|
横の空白文字にマッチします。 |
\H
|
横書き以外の文字にマッチします。 |
\v
|
縦書き空白文字にマッチします。 |
\V
|
縦書き空白でない文字にマッチします。 |
\N
|
改行でない文字にマッチします。 |
\pP ,\p{Prop}
|
指定された Unicode プロパティを持つ文字にマッチします。 |
\PP ,P{Ptop}
|
指定された Unicode プロパティを持たない文字にマッチします。 |
角括弧で囲まれた文字クラス
[編集][]
の内側をブラケットで囲んだ部分は「角括弧で囲まれた文字クラス」です。
- 書式
"Wikibooks" =~ /[abc]/ # a と c は含まれないが、b は含まれるのでマッチする
- コード例
if ("Wikibooks" =~ /[abc]/) { print "Match!"; } else { print "Not match."; }
- 実行結果
Match!
- 文字クラスのハイフン
[]
の中でハイフン -
を使うことで、文字の範囲を指定することができます。
たとえば、/[a-z]/ と書けば、英語の小文字にマッチします。(なお Perl の正規表現では、大文字と小文字を区別します。)
あるいは /[0-9]/ と書けば、十進数の数字にマッチします。
- 書式
$foo =~ /[abc]/; $foo =~ /[a-c]/; # 上の文と等価 $foo =~ /[01234]/; $foo =~ /[0-4]/; # 上の文と等価
ハイフンの前の文字は、後ろの文字よりも文字コードにおいて前でなければなりません。
- 書式
$foo =~ /[b-a]/; # エラー $foo =~ /[5-3]/; # エラー $foo =~ /[a-3]/; # エラー
- コード例
if ("Wikibooks" =~ /[a-c]/) { print "Match!ggg"; } else { print "Not matchggg."; }
- 実行結果
Match!
- エスケープ
ハイフン自体を文字クラスに含めるには、文字クラスの一番前か一番後ろに記述するか、バックスラッシュでエスケープします。(なお、Windows環境では表示で、バックスラッシュの代わりに、通貨記号の円マークが表示されるかもしれません。)
- 書式
$foo =~ /[-ab]/; # ハイフンまたは a か b にマッチする $foo =~ /[ab-]/; # 上の文と等価 $foo =~ /[a\-b]/; # 上の文と等価
開きブラケット ([) に ^ を後置すると、否定キャラクタクラスを表現することができます。
- 否定キャラクタクラス
$foo =~ /[^0-9]/; # 数字以外にマッチする
グループ化
[編集]丸括弧で括った部分はグループ化されます。
グループ化した部分は後から参照することができます。これを後方参照といいます。 同じ正規表現内で後方参照を行うには、\1, \2... を用います。
- 後方参照
$foo =~ /(abc)\1/; # abc が2回連続する文字列にマッチする
また、正規表現外で後方参照を行うには、スカラー変数 $1, $2... を用います。
- $1をつかった一致部分参照
"Wikibooks" =~ /(wiki)/i; print $1; # 'Wiki' と出力される。
選択
[編集]縦線を用いると正規表現を選択することができます。
- パターンの選択
$foo =~ /abc|def/; # abc あるいは def にマッチする
- コード例
$foo = "defabc" ; if ($foo =~ /abc|def/) { print "Match!"; } else { print "Not match."; }
- 実行結果
Match!
下記の書式例では、^ や $ が | よりも優先順位が高いため、abc で始まる文字列か def で終わる文字列にマッチします。
- コード例
$foo =~ /^abc|def$/;
- コード例
$foo = "defabc" ; if ($foo =~ /^abc|def$/) { print "Match!"; } else { print "Not match."; }
- 実行結果
Not Match.
- コード例
$foo = "abcdef" ; if ($foo =~ /^abc|def$/) { print "Match!"; } else { print "Not match."; }
- 実行結果
Match!
先頭と末尾の両方に接する「"abc"」か 「"def"」だけにマッチさせるには以下のようにします。
# カッコで両項ともククる方式 $foo =~ /^(abc|def)$/; # あるいは各項に展開する方式 $foo =~ /^abc$|^def$/;
- コード例
$foo = "defabc" ; if ($foo =~ /^abc$|^def$/) { print "Match!"; } else { print "Not match."; }
- 実行結果
Not Match.
- コード例
$foo = "def" ; if ($foo =~ /^abc$|^def$/) { print "Match!"; } else { print "Not match."; }
- 実行結果
Match!
- コード例
$foo = "def555" ; if ($foo =~ /^abc$|^def$/) { print "Match!"; } else { print "Not match."; }
- 実行結果
Not Match.
置き換え
[編集]s///演算子を用いると、文字列の置換を行うことができます。
$str = "Wikibooks"; $str =~ s/books/pedia/; # $str は "Wikipedia" になる
m//と同じく、スラッシュ以外の記号を用いることもできます。
<pre><nowiki>$foo =~ s/foo/bar/; $foo =~ s#foo#bar#; $foo =~ s@foo@bar@; $foo =~ s!foo!bar!; $foo =~ s{foo}{bar}; $foo =~ s(foo)(bar);</nowiki></pre>
修飾子
[編集]正規表現のメタキャラクター、あるいはパターンマッチそのものの振る舞いを変えるために、修飾子を指定することができます。たとえば、正規表現がアルファベットの大文字小文字を区別せずにマッチするようにするためには、
m/^perl$/i; # perlやPerl、PERL、PeRl、pErLなどにマッチする。
のように、最後のスラッシュ(あるいは何らかの記号)の後に、i修飾子を付加します。
i | 大文字小文字の同一視 (case-insensitive) |
---|---|
s | 「.」が改行にもマッチするようにする (single line) |
m | 複数行として扱う (multi-line) |
x | 拡張正規表現を使う (extended) |
e | Perlのコードとして評価する (evaluation) |
ee | Perlのコードとして2回評価する (evaluation and evaluation) |
g | 連続して何回もマッチ (global) |
o | 一度だけコンパイルする (only once) |
拡張正規表現
[編集]x修飾子を付けると正規表現内の空白や改行が無視され、「#」以降はコメントとして扱われます。
# 1と出力 print 1 if "Apple" =~ / A p p l e /x;
アトムとアサーション
[編集]「ABC」や「[0-9]」、「.*?」のように、何かにマッチする正規表現の構文をアトムといいます。最後の「.*?」は、アトム「.」に量指定子「*」、「?」が付いたもので、特に量指定子付きアトムといいます。
「^」や「$」、「|」のように、何かにマッチするわけではない正規表現の構文をアサーションといいます。
正規表現の構文は基本的にアトムとアサーションのどちらかに分けられます。ただし、\Qや\E、\uや\Uのような特殊なシーケンスはアトムでもアサーションでもありません。これらは構文のふるまいを変えるものです。
拡張構文
[編集]コメント
[編集]/(?#ここはコメント)/
クラスタ化専用カッコ
[編集](?:...)はクラスタ化(正規表現をまとめること)のみに使われるカッコです。キャプチャを行わないため、マッチした部分を正規表現の中で\1、\2のように参照したり、後から$1、$2のような変数で参照したりすることができません。キャプチャを行う必要がない場合は、このカッコを使うことで効率化を図ることができます。
"Apple" =~ /^(?:Apple|Banana|Cherry)$/; # AppleかBananaかCherryにマッチ
これにはimsx修飾子を付けることもできます。i修飾子を付けるには、i-msx(iを指定しmsxを指定しない)とします。
"aPpLe" =~ /^(?i-msx:Apple|Banana|Cherry)$/;
単に修飾子を有効または無効にするためだけにこのカッコを使うこともできます。
/A(?i-msx)B/; # Aは大文字小文字を区別するが、Bは区別しない
ルックアラウンドアサーション
[編集]ルックアラウンドアサーションとは、直後または直前にパターンが出現すること、あるいは出現しないことを確認し、確認するだけで何にもマッチしないアサーションです。
- 肯定先読み
直後にPATTERNが出現することを確認します。
/(?=PATTERN)/
- 否定先読み
直後にPATTERNが出現しないことを確認します。
/(?!PATTERN)/
次の例では、「&」以外の「&」をすべて「&」に置換します。
$str =~ s/&(?!amp;)/&/g;
- 肯定後読み
直前にPATTERNが出現することを確認します。
/(?<=PATTERN)/
- 否定後読み
直前にPATTERNが出現しないことを確認します。
/(?<!PATTERN)/
非バックトラックサブパターン
[編集]バックトラックしないPATTRENにのみマッチします。
(?>PATTERN)
コードサブパターン
[編集](?{ CODE })という形で、正規表現の中にPerlのコードを埋め込むことができます。
/(?{ print "Hello, world!\n" })/; # Hello, world!と表示
(??{ CODE })という形では、CODEを評価した結果得られた正規表現にマッチします。
"ABC" =~ /^(??{ "A"."B"."C" })$/; # ABCにマッチする
条件付き展開
[編集]Perlの条件演算子?:のように、条件が真か偽かでマッチさせるパターンを変えることができます。
/(?(COND)TRUE|FALSE)/
または
/(?(COND)TRUE)/
CONDが真の場合はTRUE、偽の場合はFALSEのパターンにマッチします。