PHPの正規表現には、
の3種類がありますが、ここではPerl互換のpregについて解説します。
関数 | 説明 | |
---|---|---|
preg_match | 正規表現によるマッチングを行う | |
preg_match_all | 繰り返し正規表現検索を行う | |
preg_grep | パターンにマッチする配列の要素を返す | |
preg_replace | 正規表現検索および置換を行う | |
preg_replace_callback | 正規表現検索を行い、コールバック関数を使用して置換を行う | |
preg_filter | 正規表現による検索と置換を行う | |
preg_split | 正規表現で文字列を分割する | |
preg_quote | 正規表現文字をクォートする | |
preg_last_error | 直近の PCRE 正規表現処理のエラーコードを返す |
正規表現のマッチモードを指定します。
修飾子 | モード | 説明 |
---|---|---|
i |
大文字と小文字の違いを無視する | |
s |
ドット全マッチ モード | |
m |
拡張行アンカーマッチ モード | メタ文字の^ と$ が、行頭と行末にマッチするようにする |
x |
フリーフォーマット モード | 文字クラス以外で、エスケープされていない空白文字を無視する |
u |
対象文字列を、UTF-8として扱う | |
e |
置換文字列を、PHPコードとして実行 | |
X |
PCREの独自機能を有効 | |
S |
PCREのstudy最適化を実行 |
修飾子はPerlなどと同様で、
/[a-z]/i
のように、区切り文字の後に記述します。
g修飾子はサポートされないため、パターンマッチではpreg_match_allを使用します。一方で置換では、既定でg修飾子を指定した場合と同じ動作をします。
\d、\w、\sなどの文字クラスの略記法が使用できます。PHPではこれを、文字型 (character types) と呼称しています。
マルチバイト文字にはmb_ereg()を使用することになりますが、対象がUTF-8ならばpregでパターン修飾子 (/u) を指定することでも対応できます。
漢字のみで構成される文字列にマッチさせるには、
preg_match( '/\p{Han}+/u', $text, $matches );
のようにします。
PHP: Unicode 文字プロパティ - Manualint preg_match ( string $pattern, // 検索するパターンを表す文字列 string $subject, // パターンマッチの対象となる文字列 [, array &$matches // マッチした文字列の配列 [, int $flags = 0 [, int $offset = 0 // 検索の開始位置 (バイト単位) ]]] )PHP: preg_match - Manual
文字列に日本語を含むならば、符号化方式をUTF-8としてUTF-8モードで処理すべきです。
マッチに成功した場合は1を、さもなくば0が返されます。エラーが発生した場合にはFALSEが返されますので、マッチの失敗の0とは区別する必要があります。$patternはPerlなどと同様に、区切り文字 (デリミタ) で囲む必要があります。
たとえば、
preg_match( '/([A-Z]+).*?([0-9]+)/', 'fooBar2000', $matches );
とすると、$matchesには次のように結果が格納されます。
Array ( [0] => Bar2000 パターン全体のマッチ部分 [1] => B 1つ目のキャプチャのマッチ部分 [2] => 2000 2つ目のキャプチャのマッチ部分 )
preg_match()のflagsに、PREG_OFFSET_CAPTUREを指定します。
preg_match( '/([A-Z]+).*?([0-9]+)/', 'fooBar2000', $matches, PREG_OFFSET_CAPTURE );
結果は次のように返されます。
Array ( [0] => Array ( [0] => Bar2000 [1] => 3 ) [1] => Array 1つ目のキャプチャのマッチ部分 ( [0] => B マッチした文字列 [1] => 3 対象文字列中における、マッチした文字列のオフセット値 ) [2] => Array 2つ目のキャプチャのマッチ部分 ( [0] => 2000 [1] => 6 ) )
int preg_match_all ( string $pattern, string $subject, [, array &$matches [, int $flags = PREG_PATTERN_ORDER [, int $offset = 0 ]]] )PHP: preg_match_all - Manual
マッチした回数が返され、マッチしなかった場合には0となります。また、エラーが発生した場合はFALSEが返されます。
preg_match_allで返される第3引数の$matchesは、
$matches[ 0 ][ n ] | n回目のパターンマッチで、パターン全体にマッチした文字列 |
---|---|
$matches[ 1 ][ n ] | n回目のパターンマッチにおける、Perlの$1と同様の内容 |
$matches[ 2 ][ n ] | n回目のパターンマッチにおける、Perlの$2と同様の内容 |
のような2次元の配列となります。このとき $matches[ 1 ]は、マッチしたすべての$1の配列になります。
n回目にパターンマッチした内容ごとに処理したい場合には、preg_match_allの$flags引数にPREG_SET_ORDERを指定します。このとき$matches[ 1 ]は、1回目のパターンマッチでマッチした$1や$2などのすべての要素の配列になります。たとえば、
preg_match_all( '/([0-9])([A-Z])/', '1A 00 2B', $matches );
とすると、$matchesには次のように格納されます。
Array ( [0] => Array パターン全体のマッチ部分 ( [0] => 1A [1] => 2B ) [1] => Array 1つ目のキャプチャのマッチ部分 ( [0] => 1 1回目のマッチ部分 [1] => 2 2回目のマッチ部分 ) [2] => Array 2つ目のキャプチャのマッチ部分 ( [0] => A [1] => B ) )
一方でPREG_SET_ORDERを指定して、
preg_match_all( '/([0-9])([A-Z])/', '1A 00 2B', $matches, PREG_SET_ORDER );
とすると、$matchesは次のようになります。
Array ( [0] => Array 1回目のマッチ部分 ( [0] => 1A パターン全体のマッチ部分 [1] => 1 1つ目のキャプチャのマッチ部分 [2] => A 2つ目のキャプチャのマッチ部分 ) [1] => Array 2回目のマッチ部分 ( [0] => 2B [1] => 2 [2] => B ) )
またPREG_SET_ORDERを指定しない状態で、
preg_match_all( '/(AA)(BB)/', 'foo', $matches );
のように2つのかっこがある正規表現で、1つもマッチしないと次のようになります。
Array ( [0] => Array パターン全体のマッチ部分 ( ) [1] => Array 1つ目のキャプチャのマッチ部分 ( ) [2] => Array 2つ目のキャプチャのマッチ部分 ( ) )
このときpreg_match_all()は0を返します。
preg_match()でもマッチ位置の取得を行うことで、マッチするすべての文字列を取得できます。preg_match_all()でも同様のことができますが、こちらの方法の方がより柔軟に処理できます。
$result = array(); $offset = 0; while( preg_match( $pattern, $subject, $matches, PREG_OFFSET_CAPTURE, $offset ) ) { $match = $matches[ 0 ]; $result[] = $match[ 0 ]; $offset = $match[ 1 ] + strlen( $match[ 0 ] ); }
mixed preg_replace ( mixed $pattern, // 検索するパターンを表す文字列または配列 mixed $replacement, // 置き換える文字列または文字列の配列 mixed $subject // 置換対象の文字列または文字列の配列 [, int $limit = -1 // 置換を行う最大回数 (-1は無制限) [, int &$count ]] // 置換が行われた回数を返す )PHP: preg_replace - Manual ※[ ]で囲まれた項目は省略可能です。
文字列に日本語を含むならば、符号化方式をUTF-8としてUTF-8モードで処理すべきです。
既定で、マッチするすべての文字が置換されます。1つだけ置換したいならば、引数の$limitに1を指定します。
マッチの結果によって、次のように戻り値が異なります。
簡単な置換ならば文字列の関数 (str_replace) でも処理できます。
$subject = 'abc 123 45';
$str = preg_replace( '/[0-9]/', 'B', $subject );
echo $str; // abc BBB BB
$subject = 'abc 123 45';
$str = preg_replace( '/([0-9])/', '($1)', $subject );
echo $str; // abc (1)(2)(3) (4)(5)
$subject = array( 'abc', 123, 45 ); $str = preg_replace( '/[0-9]/', 'B', $subject ); print_r( $str ); // Array // ( // [0] => abc // [1] => BBB // [2] => BB // )
$patterns = array( '/[a-z]/', '/[0-9]/' );
$replacements = array( 'A', 'B' );
$subject = 'abc 123 456';
$str = preg_replace( $patterns, $replacements, $subject );
echo $str; // AAA BBB BB
複雑は置換処理はpreg_replace_callback()によって実現できます。この関数はマッチした文字に対して、独自に定義した関数で置換文字列を決定します。
mixed preg_replace_callback ( mixed $pattern , callable $callback , mixed $subject [, int $limit = -1 [, int &$count ]] )PHP: preg_replace_callback - Manual
pregの正規表現エンジンでは、正規表現を区切り文字で囲まなければなりません。一般的にはスラッシュ (/) が使用されますが、実際には英数字とバックスラッシュ以外ならば何でも構いません。たとえば、
/[0-9]/
これは、次のように記述しても同じです。
<[0-9]>
正規表現のなかで区切り文字と同一文字を使用するにはエスケープしなければなりませんが、区切り文字を変更するとそれが不要となるため、この手法が役に立ちます。
\
) へのマッチバックスラッシュにマッチさせるには、これが正規表現ではエスケープの記号として使用されていることから、これ自体をエスケープして「\\
」と記述する必要があります。またPHPの文字列リテラルでもバックスラッシュがエスケープに使用されるため、同様に「\\
」とする必要があります。
よってPHPの文字列リテラルで記述された正規表現でバックスラッシュにマッチさせるには、「\\\\
」とします。
?>
)正規表現のパターン中に「?>
」と記述した場合、エディタによってはPHPスクリプトの終了タグとみなされる場合があります。その場合にはASCIIコードで記述することで、この問題を回避できます。