• 追加された行はこの色です。
  • 削除された行はこの色です。
[[PHP]]

#norelated

PHPで、正規表現(パターンマッチ)を使おう!

#contents

* 正規表現とは? [#efc910d2]
[[正規表現 - Wikipedia>http://ja.wikipedia.org/wiki/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E7%8F%BE]]
>正規表現(せいきひょうげん、regular expression)とは、文字列の集合を一つの文字列で表現する方法の一つである。

[[正規表現とは【regular expression】 - IT用語辞典>http://e-words.jp/w/E6ADA3E8A68FE8A1A8E78FBE.html]]
>文字列のパターンを表現する表記法。文字列の検索・置換を行うときに利用される。

* 参考リンク [#vb592918]
| PHP 正規表現の基本 (preg_match) - どうにかなるBLOG | http://sandman.s6.xrea.com/nucleus/item-62.html |
| サルにもわかる正規表現入門 | http://www.mnet.ne.jp/~nakama/ |
| 正規表現の解説 初級編 | http://www4.ocn.ne.jp/~kaerume/k2e/regex_1.html |
| 図解でみる正規表現入門 | http://funcchan.blog16.fc2.com/ |
| 正規表現/PHP入門 | http://www.scollabo.com/banban/php/php_15.html |
| よく使う正規表現 - PHP入門(正規表現3) - イクケン | http://labo.iix.co.jp/?p=573 |

* PHPの正規表現 [#pe85aadc]
PHPでは、正規表現を扱う関数が3種類用意されています。
http://www.php.net/manual/ja/refs.basic.text.php

| 関数 | 機能 | マルチバイト文字 |h
| [[POSIX拡張正規表現関数>http://www.php.net/manual/ja/book.regex.php]] | POSIX拡張正規表現を使用した正規表現関数 | マルチバイト文字には対応していない |
| [[PCRE関数>http://www.php.net/manual/ja/book.pcre.php]] | Perlの正規表現に似た構文を持つ正規表現関数 | UTF-8には対応しているが、他のマルチバイト文字には対応していない |
| [[マルチバイト文字列関数>http://php.net/manual/ja/ref.mbstring.php]] | マルチバイト対応の文字列関数(mbstring)の正規表現関数 | マルチバイト文字に対応している |

- [[POSIX>http://e-words.jp/w/POSIX.html]] = Portable Operating System Interface for UNIX の略。
UNIXベースのOSが備えるべき最低限の仕様のセット。
POSIX正規表現は、UNIXで使われている正規表現をベースにしている。

- POSIX正規表現は非推奨
http://www.php.net/manual/ja/reference.pcre.pattern.posix.php
>PHP 5.3.0 以降、POSIX 正規表現 拡張モジュールは非推奨となりました。

- [[PCRE>http://ja.wikipedia.org/wiki/Perl_Compatible_Regular_Expressions]] = Perl Compatible Regular Expressions の略。
PHPでは、POSIX互換の正規表現関数よりも、Perl互換の正規表現関数やマルチバイト文字列関数の正規表現関数の使用が推奨されているようです。

** POSIX 正規表現関数 [#vec1d18c]
http://www.php.net/manual/ja/ref.regex.php

| ereg_replace | 正規表現による置換を行う |
| ereg | 正規表現によるマッチングを行う |
| eregi_replace | 大文字小文字を区別せずに正規表現による置換を行う |
| eregi | 大文字小文字を区別せずに正規表現によるマッチングを行う |
| split | 正規表現により文字列を分割し、配列に格納する |
| spliti | 大文字小文字を区別しない正規表現により文字列を分割し、配列に格納する |
| sql_regcase | 大文字小文字を区別しないマッチングのための正規表現を作成する |

** PCRE(Perl互換正規表現)関数 [#t9ccbf8f]
http://www.php.net/manual/ja/book.pcre.php

| preg_filter | 正規表現による検索と置換を行う |
| preg_grep | パターンにマッチする配列の要素を返す |
| preg_last_error | 直近の PCRE 正規表現処理のエラーコードを返す |
| [[preg_match_all>http://www.php.net/manual/ja/function.preg-match-all.php]] | &color(red){繰り返し正規表現検索を行う};  |
| [[preg_match>http://www.php.net/manual/ja/function.preg-match.php]] | &color(red){正規表現によるマッチングを行う};  |
| preg_quote | 正規表現文字をクオートする |
| preg_replace_callback | 正規表現検索を行い、コールバック関数を使用して置換を行う |
| preg_replace | 正規表現検索および置換を行う |
| preg_split | 正規表現で文字列を分割する |

** マルチバイト文字列関数 [#u9e5785d]
http://php.net/manual/ja/ref.mbstring.php

| mb_ereg_match | マルチバイト文字列が正規表現に一致するか調べる |
| mb_ereg_replace | マルチバイト文字列に正規表現による置換を行う |
| mb_ereg_search_getpos | 次の正規表現検索を開始する位置を取得する |
| mb_ereg_search_getregs | マルチバイト文字列が正規表現に一致する部分があるか調べる |
| mb_ereg_search_init | マルチバイト正規表現検索用の文字列と正規表現を設定する |
| mb_ereg_search_pos | 指定したマルチバイト文字列が正規表現に一致する部分の位置と長さを返す |
| mb_ereg_search_regs | 指定したマルチバイト文字列が正規表現に一致する部分を取得する |
| mb_ereg_search_setpos | 次の正規表現検索を開始する位置を設定する |
| mb_ereg_search | 指定したマルチバイト文字列が正規表現に一致するか調べる |
| mb_ereg | マルチバイト文字列に正規表現マッチを行う |
| mb_eregi_replace | マルチバイト文字列に大文字小文字を区別せずに正規表現による置換を行う |
| mb_eregi | マルチバイト文字列に大文字小文字を区別しない正規表現マッチを行う |
| mb_regex_encoding | 現在の正規表現用のエンコーディングを文字列として返す |
| mb_regex_set_options | マルチバイト正規表現関数のデフォルトオプションを取得または設定する |
| mb_split | マルチバイト文字列を正規表現により分割する |

* PCREのパターン構文 [#jc4e7be3]
http://php.net/manual/ja/reference.pcre.pattern.syntax.php

以下、preg_match()等、PCRE関数の使い方のまとめです。
PHPマニュアルの和訳は、ちょっと文章が硬くて分かりづらいですね><

** デリミタ [#j49d8c04]
http://www.php.net/manual/ja/regexp.reference.delimiters.php
>PCRE 関数を使うときには、パターンを delimiters で囲まなければなりません。
英数字、バックスラッシュ、空白文字以外の任意の文字をデリミタとして使うことができます。
デリミタとしてよく使われる文字は、スラッシュ (/)、 ハッシュ記号 (#) およびチルダ (~) です。
次に示す例は、どれも正しいデリミタです。

#code(php){{
/foo bar/
#^[^0-9]$#
+php+
%[a-zA-Z0-9_-]%
}}

-用語:デミリタ(delimiter) = 「区切り」を意味する記号、文字のこと。
-正規表現で文字列のパターンを指定するとき、パターンの前後をデミリタの記号で囲んで、パターンであることを明示する。
-通常、デミリタの記号として「/」(スラッシュ)という文字がよく使われる。

 例: $pattern = '/abc/';

** メタ文字 [#w73b17aa]
メタ文字=文字列の構造(文字の繰り返し等)を表現するために使われる特殊文字の事。

http://www.php.net/manual/ja/regexp.reference.meta.php
>正規表現の強力さは、パターン中に&color(red){選択肢};や&color(red){繰り返し};を記述できることにあります。
選択肢や繰り返しは、メタ文字 (meta-character) を使ってパターン中に記述します。
メタ文字は、その文字自体を表わさず、代わって特別な解釈が行われます。

>メタ文字には、2種類あります。
ひとつは、角カッコ内を除き、パターン中のどこででも使用できる文字です。
もうひとつは、角カッコで括られた中でだけ使用できる文字です。

*** 角カッコの外で使用できるメタ文字 [#s8fd7896]

| メタ文字 | 機能 |h
| \ | 多目的に使う一般的なエスケープ文字 |
| ^ | 検索対象(複数行モードでは行)の始まりを言明 |
| $ | 検索対象(複数行モードでは行)の終わりを言明 |
| . | 改行を除くすべての文字にマッチ(デフォルト時) |
| [ | 文字クラス定義の開始 |
| ] | 文字クラス定義の終了 |
| | | 選択枝の開始 |
| ( | サブパターンの開始 |
| ) | サブパターンの終了 |
| ? | ( の意味を拡張/0 または 1 回マッチ/なるべく少ない回数だけマッチ (繰り返し を参照) |
| * | 0回以上の繰り返し |
| + | 1回以上の繰り返し |
| { | 最小/最大を指定する量指定子の開始 |
| } | 量指定子の終了 |

*** 角カッコの内で使用できるメタ文字 [#od62c9ef]

パターン中の角カッコで括まれた部分を「&color(red){文字クラス};」と言います。 文字クラスで使えるメタ文字は、次のものだけです。

| メタ文字 | 機能 |h
| \ | 一般的なエスケープ文字 |
| ^ | クラスの否定。ただし、文字クラスの最初の文字に用いた場合のみ |
| - | 文字の範囲の指定 |
| ] | 文字クラスの終了 |

*** 「メタ」とは? [#tfacf0ea]
メタ文字の「メタ」(meta)とは、「超」という意味。

http://www.mnet.ne.jp/~nakama/regexp1.html
>特殊文字を正規表現では、「メタ文字」と呼んでいます。
「メタ」というのは、「超」と言う意味で、あの「チョーむかつく」の「チョー」と同じ意味です。
普通の文字以上の意味を含んでいるという意味になるかと思います。 

** エスケープシーケンス [#m4e75d1d]
http://www.php.net/manual/ja/regexp.reference.escape.php

*** メタ文字の処理 [#gf10ded8]
正規表現で使われるメタ文字(「*」や「+」等の文字)を、正規表現のパターンとして使いたい場合、エスケープ文字(英語環境ではバックススラッシュ=半角の「\」、日本語環境では円記号=半角の「¥」)を前に付けると、メタ文字ではなく普通の文字として扱える。

>バックスラッシュ〔日本語環境では円記号となる場合もある〕には、 いくつかの使用法があります。
ひとつめの使用法は、非英数字の前に記述する場合で、続く文字が表す特別な意味を取り去ります。
このエスケープ文字としての使用法は、文字クラスの内外部いずれでも可能です。

 例: $pattern = '/12\*89/';

-「*」の意味が変わる。
-「0回以上の繰り返し」を意味するメタ文字の「*」としてではなく、ただの文字のアスタリスク「*」として扱える。
-パターン /12\*89/ は、「12*89」という文字列にマッチする。

*** 非表示文字の指定 [#i204f0a6]
検索・置換したい文字列の中に、改行やタブなどの非表示文字がある場合、エスケープシーケンスを使う。

>バックスラッシュの 2 番目の使用法は、非表示文字〔制御コードなど〕をパターン中に目に見える形で記述するための方法です。
ヌル文字はパターンを終了させてしまうため使えませんが、その他の非表示文字は、パターンにそのまま含めても問題はありません。しかし、パターンの編集には、バイナリ文字をそのまま用いるよりも、以下に示すエスケープシーケンスを用いる方が便利でしょう。

(例)
| エスケープシーケンス | 意味 |h
| \n | 改行 (newline) |
| \t | タブ |

*** 文字型の指定 [#p4639179]
>バックスラッシュの第3の使用法は、包括的な文字型を指定する用途です。

(例)
| エスケープシーケンス | 意味 |h
| \d | 10進数字 |
| \s | 空白文字 |

*** 条件指定 [#hfa78ab3]
>バックスラッシュの第 4 の使用法は、簡単な言明 (assertion) です。
言明とは、マッチがある特定の位置でだけ可能だという条件を指定するもので、検索対象文字列から文字を消費 (consume)〔つまり文字自体にマッチ〕しません。
サブパターンを使ったより複雑な言明の方法もありますが、それについての解説は後ほど行います。
バックスラッシュを使った言明は、次のものがあります 

(例)
| エスケープシーケンス | 意味 |h
| \G | マッチングの開始位置 |
| \A | 検索対象文字列の始端(複数行モードとは独立) |
| \Z | 検索対象文字列の終端、または終端の改行(複数行モードとは独立) |

http://www4.ocn.ne.jp/~kaerume/k2e/regex_1.html#b3_3
>\A
文字列の最初
文字列の最初にマッチします。
マッチ対象文字列が複数行になっていても、その文字列の一番最初の位置にだけマッチします。

>\Z
文字列の最後
文字列の最後にマッチします。
マッチ対象文字列が複数行になっていても、その文字列の一番最後の位置にだけマッチします。

** Unicode 文字プロパティ [#f8d88ef6]
http://www.php.net/manual/ja/regexp.reference.unicode.php

** アンカー [#s786b6be]
アンカーは、文字列内の特定の位置(行頭、行末など)を表すもの。
通常、マッチするのは「文字」に対してだが、アンカーは「位置」に対してマッチする。

http://www.php.net/manual/ja/regexp.reference.anchors.php
>ハット記号 (^)
マッチング位置が対象文字列の始端

>ドル記号 ($)
マッチング位置が 対象文字列の終端にあるか、文字列の終わりの改行文字の直前にある場合

http://www4.ocn.ne.jp/~kaerume/k2e/regex_1.html#b3_3
> ^
行頭
行のはじめの位置にマッチします。始めの文字ではありませんので注意して下さい。
\n」の次(文字列があれば)には必ず「^」があることになります。

> $
行末
行の終端位置にマッチします。終わりの文字ではありません。

** ドット [#e59060d7]
http://www.php.net/manual/ja/regexp.reference.dot.php
>パターン中のドット(ピリオド、終止符)は、文字クラス外では、対象文字列の任意の 1文字にマッチします。
非出力文字も含まれます。
ただし、(デフォルトでは)改行文字とはマッチしません。

http://www4.ocn.ne.jp/~kaerume/k2e/regex_1.html#b3_2
「.」(ピリオド)は、改行を除く任意の1文字を表す。

** 文字クラス [#y1a1ecfb]
http://www.php.net/manual/ja/regexp.reference.character-classes.php
>開き角カッコは文字クラス (character class) の開始を表し、閉じ角カッコにより文字クラスは終了します。
閉じ角カッコだけでは、特別な意味を持ちません。
閉じ角カッコを文字クラスのメンバとしたい場合は、文字クラスの最初の文字(否定のハット記号がある場合はその直後)とするか、バックスラッシュでエスケープする必要があります。

>文字クラスは、検索対象文字列のたかだか1文字にマッチします。
マッチする文字は、その文字クラスによって定義された文字集合のうちのどれかです。
ただし、文字クラスの最初の文字がハット記号の場合は、マッチする文字は、その文字クラスに定義されていない文字となります。
ハット記号自体をクラスのメンバとしたい場合は、文字クラスの最初の文字としないか、バックスラッシュでエスケープしてください。

ワォ~!PHPマニュアルの文章は硬い!(訳分からんw)

** 選択肢 [#i353b515]
http://www.php.net/manual/ja/regexp.reference.alternation.php
>縦線は、パターンに選択肢 (alternative) を列挙するために使われます。
例えば、パターン
 gilbert|sullivan
は、"gilbert" または "sullivan" にマッチします。
選択肢の数に制限はありません。
また、空の選択肢も可能です (空の文字列にマッチします)。
マッチの手順としては、各選択肢が左から右に順にマッチするかどうか試行され、最初にマッチに成功した選択肢が使われます。

** 内部オプション設定 [#kcd7c294]
http://www.php.net/manual/ja/regexp.reference.internal-options.php

** サブパターン [#ma301739]
http://www.php.net/manual/ja/regexp.reference.subpatterns.php
>サブパターンは、丸カッコで括られたパターンのことで、ネストも可能です。
パターンの一部をサブパターンにすると、以下の 2 つのことが可能になります。

> 1.選択肢の範囲の指定 (localize)。
例えば、パターン cat(aract|erpillar|) は、単語 "cat", "cataract", "caterpillar" にマッチします。
カッコをつけないと、このパターンは、"cataract", "erpillar" または空の文字列にマッチしてしまいます。

> 2.サブパターンによる値の取得(キャプチャ)。
パターン全体としてマッチに成功した場合、対象文字列の内、サブパターンにマッチした部分の値がコールした側に (pcre_exec() の引数 ovector で) 返されます。
開きカッコの数が(1 から始まって)左から右に数えられ、キャプチャ用サブパターン (capturing subpattern) の番号が指定されます。

>例えば、文字列 "the red king" に対し、パターン
 the ((red|white) (king|queen))
をマッチングさせた場合、キャプチャされる部分文字列は、 "red king", "red", "king" であり、 それぞれ 1 番, 2 番, 3 番と番号がふられます。 

** 繰り返し [#l3b26f20]
http://www.php.net/manual/ja/regexp.reference.repetition.php
>繰り返し (repetition) は、量指定子 (quantifier) を使って指定します。
量指定子は、以下の要素の後に付けることが出来ます。

- 個々の文字。エスケープされた文字も含む
- メタ文字「.」(ドット)
- 文字クラス
- 後方参照
- カッコで括られたサブパターン(言明は除く)

** 後方参照 [#mb0ab15d]
http://www.php.net/manual/ja/regexp.reference.back-references.php

** 言明 [#ib2d5e45]
http://www.php.net/manual/ja/regexp.reference.assertions.php

>言明 (assertion) とは、カレントのマッチング位置の直前・直後の文字に対する テストであり、文字を消費 (consume)〔つまり文字自体にマッチ〕しません。
単純な言明コード \b, \B, \A, \Z, \z, ^ および $ については、前述しました。
より複雑な言明は、サブパターンを用いて記述します〔言明サブパターン (assertion subpattern) と呼ばれる〕。
言明サブパターンには、2種類あります。
対象文字列においてカレントの位置の先を読むものと、後ろを読むものです。

>'''先読み'''言明 (lookahead assertion) は、 肯定の言明 (positive assertion) の場合 (?= で始まり、 否定の言明 (negative assertion) の場合 (?! で始まります。

>'''戻り読み'''言明は、肯定の言明の場合 (?<= で始まり、 否定の言明の場合 (?<! で始まります。

(参考)
http://www.upken.jp/kb/ybAuLxOIsfZvLHlCyOJlRhjyOMKBHa.html

** 再試行無しのサブパターン [#vbac7f3b]
http://www.php.net/manual/ja/regexp.reference.onlyonce.php

** 条件付きサブパターン [#tad92959]
http://www.php.net/manual/ja/regexp.reference.conditional.php

** コメント [#od6cb528]
http://www.php.net/manual/ja/regexp.reference.comments.php

** 再帰的パターン [#f90eaeaf]
http://www.php.net/manual/ja/regexp.reference.recursive.php

** パフォーマンス [#m57faa8d]
http://www.php.net/manual/ja/regexp.reference.performance.php


* 参考書 [#icaa995e]

#html{{
<table border="0" cellpadding="5"><tr><td valign="top">
<a href="http://www.amazon.co.jp/exec/obidos/ASIN/4839927073/sagasite-22/"><img src="http://ecx.images-amazon.com/images/I/41y%2Bbfj9ICL._SL160_.jpg" border="0"></a>
</td>
<td valign="top">
<a href="http://www.amazon.co.jp/exec/obidos/ASIN/4839927073/sagasite-22/">PHPマスターブック PHP5対応</a>
<br>
坂田 健二<br>
毎日コミュニケーションズ<br>
2008-03-27<br>
</td></tr></table>
}}

サンプルコードは、「preg_match」関数の使用例に変更しました。

** 文字クラスの使用 [#i1449b29]
>「0~9の数字のいずれか」や「a~zの英小文字のいずれか」のように、いくつかの文字の中の1つにマッチすればいい場合には&color(red){文字クラス};を使用します。文字クラスでは[]内にマッチさせたい文字を記述します。

#code(php){{
<?php
$target = '123abc';
$pattern = '/[0123456789][0123456789]/';
$result = preg_match($pattern, $target);
if ($result) {
  echo $target."には2桁の数字が含まれています。";
} else {
  echo $target."には2桁の数字が含まれていません。";
}
}}

** メタ文字 [#ne37074d]
| メタ文字 | 説明 |h
| \d | 数字の1文字を表す(文字クラス[0-9]と同じ)|
| \D | 数字以外の1文字を表す(文字クラス[^0-9]と同じ)|
| \w | 英数字、アンダースコアの1文字を表す(文字クラス[a-zA-Z_0-9]と同じ)|
| \W | 英数字、アンダースコア以外の1文字を表す(文字クラス[^a-zA-Z_0-9]と同じ)|
| \s | 空白文字(半角スペース、タブ、改行文字)を表す(文字クラス[\n\r\f\t]と同じ)|
| \S | 空白文字(半角スペース、タブ、改行文字)以外を表す(文字クラス[^\n\r\f\t]と同じ)|

#code(php){{
<?php
$target = '123abc';
$pattern = '/\d\d/';
$result = preg_match($pattern, $target);
if ($result) {
  echo $target."には2桁の数字が含まれています。";
} else {
  echo $target."には2桁の数字が含まれていません。";
}
}}

** 文字の繰り返しを表す(量指示子) [#jc4d3ce2]
>パターンマッチで直前のパターン(文字)が何回繰り返すがを指定するには次表に示す量指示子や、「.」(ドット)を使って記述することができます。
(「.」は改行文字を除く任意の1文字を表すメタ文字です。)

| 量指示子 | 繰り返す回数 |h
| * | 0回以上繰り返す |
| + | 1回以上繰り返す |
| ? | 0回もしくは1回以上繰り返す |
| {m} | m回繰り返す |
| {m,} | m回以上繰り返す |
| {m.n} | m回以上、n回以下繰り返す |

#code(php){{
<?php
$target = 'body';
$pattern = '/b.+y/';
$result = preg_match($pattern, $target, $matches);
if ($result) {
  echo $target."は「b.+y」にマッチします";
  var_dump($matches);
} else {
  echo $target."は「b.+y」にマッチしません";
}
}}

** マッチさせる位置を指定する(位置指示子) [#lddd0de8]
>パターンマッチでマッチさせる位置を指定するには次表に示す位置指示子を使用します。
「^」をパターンの先頭に記述した場合は、「行の先頭」という意味になりますが、パターンの先頭以外に「^」を記述すると文字の「^」として扱われます(文字クラスの先頭に記述すると「^」は否定の意味になります)。
パターンの先頭で「^」を文字の「^」として認識させるには「\^」と記述してください。
また同様にパターンの最後の文字の「$」を記述するには「\$」としてください。

| 位置指示子 | 指定位置 |h
| ^ | 行の先頭 |
| $ | 行の末尾 |
| \A | 文字列の先頭 |
| \Z | 文字列の末尾 |
| \b | 単語区切り |
| \B | 単語区切り以外 |

例えば、「a」から始まって「b」で終わるパターンは「^a.*b$」のように記述します。

#code(php){{
<?php
$target = 'a123b';
$pattern = '/^a.*b$/';
$result = preg_match($pattern, $target);
if ($result) {
  echo $target."は「^a.*b$」にマッチします。";
} else {
  echo $target."は「^a.*b$」にマッチしません。";
}
}}

** パターンにor条件を記述する [#w9149373]
>「'abc'または'xyz'にマッチする」というようなor条件をパターンに記述したい場合には「|」を使用します。

「butterfly」または「butterflies」にマッチするというパターン

#code(php){{
<?php
$target = 'Perfume butterfly';
$pattern = '/butterfl(y|ies)/';
$result = preg_match($pattern, $target);
if ($result) {
  echo $target."にはbutterflyもしくはbutterfliesが含まれています。";
} else {
  echo $target."にはbutterflyもしくはbutterfliesが含まれていません。";
}
}}

** サブパターン [#fb58cf96]
| () | パターンをグループ化する。 |

* ツール [#ee496f5b]
PHP正規表現チェッカー ver1.0.3
http://www.rider-n.sakura.ne.jp/regexp/regexp.php



トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS