PHP

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

正規表現とは?

正規表現 - Wikipedia

正規表現(せいきひょうげん、regular expression)とは、文字列の集合を一つの文字列で表現する方法の一つである。

参考リンク

PHP 正規表現の基本 (preg_match) - どうにかなるBLOGhttp://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の正規表現

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

関数機能マルチバイト文字
POSIX拡張正規表現関数POSIX拡張正規表現を使用した正規表現関数マルチバイト文字には対応していない
PCRE関数Perlの正規表現に似た構文を持つ正規表現関数UTF-8には対応しているが、他のマルチバイト文字には対応していない
マルチバイト文字列関数マルチバイト対応の文字列関数(mbstring)の正規表現関数マルチバイト文字に対応している
  • POSIX = Portable Operating System Interface for UNIX の略。
    UNIXベースのOSが備えるべき最低限の仕様のセット。
    POSIX正規表現は、UNIXで使われている正規表現をベースにしている。
  • PCRE = Perl Compatible Regular Expressions の略。
    PHPでは、POSIX互換の正規表現関数よりも、Perl互換の正規表現関数やマルチバイト文字列関数の正規表現関数の使用が推奨されているようです。

POSIX 正規表現関数

http://www.php.net/manual/ja/ref.regex.php

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

PCRE(Perl互換正規表現)関数

http://www.php.net/manual/ja/book.pcre.php

preg_filter正規表現による検索と置換を行う
preg_grepパターンにマッチする配列の要素を返す
preg_last_error直近の PCRE 正規表現処理のエラーコードを返す
preg_match_all繰り返し正規表現検索を行う
preg_match正規表現によるマッチングを行う
preg_quote正規表現文字をクオートする
preg_replace_callback正規表現検索を行い、コールバック関数を使用して置換を行う
preg_replace正規表現検索および置換を行う
preg_split正規表現で文字列を分割する

マルチバイト文字列関数

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のパターン構文

http://php.net/manual/ja/reference.pcre.pattern.syntax.php

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

デリミタ

http://www.php.net/manual/ja/regexp.reference.delimiters.php

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

  1
  2
  3
  4
/foo bar/
#^[^0-9]$#
+php+
%[a-zA-Z0-9_-]% 
  • 用語:デミリタ(delimiter) = 「区切り」を意味する記号、文字のこと。
  • 正規表現で文字列のパターンを指定するとき、パターンの前後をデミリタの記号で囲んで、パターンであることを明示する。
  • 通常、デミリタの記号として「/」(スラッシュ)という文字がよく使われる。
例: $pattern = '/abc/';

メタ文字

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

http://www.php.net/manual/ja/regexp.reference.meta.php

正規表現の強力さは、パターン中に選択肢繰り返しを記述できることにあります。
選択肢や繰り返しは、メタ文字 (meta-character) を使ってパターン中に記述します。
メタ文字は、その文字自体を表わさず、代わって特別な解釈が行われます。

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

角カッコの外で使用できるメタ文字

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

角カッコの内で使用できるメタ文字

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

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

「メタ」とは?

メタ文字の「メタ」(meta)とは、「超」という意味。

http://www.mnet.ne.jp/~nakama/regexp1.html

特殊文字を正規表現では、「メタ文字」と呼んでいます。
「メタ」というのは、「超」と言う意味で、あの「チョーむかつく」の「チョー」と同じ意味です。
普通の文字以上の意味を含んでいるという意味になるかと思います。

エスケープシーケンス

http://www.php.net/manual/ja/regexp.reference.escape.php

メタ文字の処理

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

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

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

非表示文字の指定

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

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

(例)

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

文字型の指定

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

(例)

エスケープシーケンス意味
\d10進数字
\s空白文字

条件指定

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

(例)

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

http://www4.ocn.ne.jp/~kaerume/k2e/regex_1.html#b3_3

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

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

Unicode 文字プロパティ

http://www.php.net/manual/ja/regexp.reference.unicode.php

アンカー

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

http://www.php.net/manual/ja/regexp.reference.anchors.php

ハット記号 (^)
マッチング位置が対象文字列の始端

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

http://www4.ocn.ne.jp/~kaerume/k2e/regex_1.html#b3_3

^
行頭
行のはじめの位置にマッチします。始めの文字ではありませんので注意して下さい。
\n」の次(文字列があれば)には必ず「^」があることになります。

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

ドット

http://www.php.net/manual/ja/regexp.reference.dot.php

パターン中のドット(ピリオド、終止符)は、文字クラス外では、対象文字列の任意の 1文字にマッチします。
非出力文字も含まれます。
ただし、(デフォルトでは)改行文字とはマッチしません。

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

文字クラス

http://www.php.net/manual/ja/regexp.reference.character-classes.php

開き角カッコは文字クラス (character class) の開始を表し、閉じ角カッコにより文字クラスは終了します。
閉じ角カッコだけでは、特別な意味を持ちません。
閉じ角カッコを文字クラスのメンバとしたい場合は、文字クラスの最初の文字(否定のハット記号がある場合はその直後)とするか、バックスラッシュでエスケープする必要があります。

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

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

選択肢

http://www.php.net/manual/ja/regexp.reference.alternation.php

縦線は、パターンに選択肢 (alternative) を列挙するために使われます。
例えば、パターン

gilbert|sullivan

は、"gilbert" または "sullivan" にマッチします。
選択肢の数に制限はありません。
また、空の選択肢も可能です (空の文字列にマッチします)。
マッチの手順としては、各選択肢が左から右に順にマッチするかどうか試行され、最初にマッチに成功した選択肢が使われます。

内部オプション設定

http://www.php.net/manual/ja/regexp.reference.internal-options.php

サブパターン

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 番と番号がふられます。

繰り返し

http://www.php.net/manual/ja/regexp.reference.repetition.php

繰り返し (repetition) は、量指定子 (quantifier) を使って指定します。
量指定子は、以下の要素の後に付けることが出来ます。

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

後方参照

http://www.php.net/manual/ja/regexp.reference.back-references.php

言明

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

再試行無しのサブパターン

http://www.php.net/manual/ja/regexp.reference.onlyonce.php

条件付きサブパターン

http://www.php.net/manual/ja/regexp.reference.conditional.php

コメント

http://www.php.net/manual/ja/regexp.reference.comments.php

再帰的パターン

http://www.php.net/manual/ja/regexp.reference.recursive.php

パフォーマンス

http://www.php.net/manual/ja/regexp.reference.performance.php

参考書

PHPマスターブック PHP5対応
坂田 健二
毎日コミュニケーションズ
2008-03-27

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

文字クラスの使用

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

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

メタ文字

メタ文字説明
\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]と同じ)
  1
  2
  3
  4
  5
  6
  7
  8
  9
<?php
$target = '123abc';
$pattern = '/\d\d/';
$result = preg_match($pattern, $target);
if ($result) {
  echo $target."には2桁の数字が含まれています。";
} else {
  echo $target."には2桁の数字が含まれていません。";
}

文字の繰り返しを表す(量指示子)

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

量指示子繰り返す回数
*0回以上繰り返す
+1回以上繰り返す
?0回もしくは1回以上繰り返す
{m}m回繰り返す
{m,}m回以上繰り返す
{m.n}m回以上、n回以下繰り返す
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
<?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」にマッチしません";
}

マッチさせる位置を指定する(位置指示子)

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

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

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

  1
  2
  3
  4
  5
  6
  7
  8
  9
<?php
$target = 'a123b';
$pattern = '/^a.*b$/';
$result = preg_match($pattern, $target);
if ($result) {
  echo $target."は「^a.*b$」にマッチします。";
} else {
  echo $target."は「^a.*b$」にマッチしません。";
}

パターンにor条件を記述する

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

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

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

サブパターン

()パターンをグループ化する。

ツール

PHP正規表現チェッカー ver1.0.3
http://www.rider-n.sakura.ne.jp/regexp/regexp.php


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2017-05-25 (木) 15:55:28 (206d)