【PHP】正規表現メモ

こちらのサイトではDRUPAL10に関連する記事を掲載しています。

PHPのpreg_matchやpreg_match_allで正規表現を使って検索または置換する場合に参考になるTIPSです。

文字列内に指定したパターンの文字列が存在するか確認する

ある文字列から指定したパターンの文字列が存在するか確認するサンプルコードです。preg_match 関数は、一つでもパターンにマッチした文字列を検出すると処理を直ちに終了しますが、 preg_match_all  関数は、すべての文字列を検証します。複数のパターンの一致を検出した場合はすべての結果をリターンします。

$subject = "php5 perl5 apache1.3 apache2.2";  // 検出対象の文字列
$pattern = '/apache/';                        // 検出パターン

$match_num = preg_match($pattern, $subject, $matches);
var_dump($match_num); // int 1
var_dump($matches);
// array
//   0 => string 'apache' (length=6)

$match_num = preg_match_all($pattern, $subject, $matches);
var_dump($match_num); // int 2
var_dump($matches);
// array
//   0 => 
//     array
//       0 => string 'apache' (length=6)
//       1 => string 'apache' (length=6)

大文字・小文字を区別しない

特に指定しない場合は正規表現は大文字・小文字を区別します。大文字・小文字を区別せずにパターン検出する場合はパターン文字列の最後に ” i ” を付加します。

$subject = "php5 perl5 apache1.3 apache2.2";

$pattern = '/Apache/';      // 検出パターン(大文字・小文字を区別する)
$match_num = preg_match($pattern, $subject, $matches);
var_dump($match_num);   // int 0
var_dump($matches);     // array empty

$pattern = '/APACHE/i';
$match_num = preg_match($pattern, $subject, $matches); // 検出パターン(大文字・小文字を区別しない)
var_dump($match_num); // int 1
var_dump($matches);  // array 0 => string 'apache' (length=6) 

対象文字列の先頭から一致するか確認する

正規表現 ‘ ^ ‘ を使用することにより、対象文字列の先頭から一致しているか確認することができます。 何も指定していない場合は、対象文字列内のどこに存在していてもパターンと一致するとみなされます。

$subject = "php5 perl5 apache 1.3 apache2.2";    // 検索対象文字列

// パターン文字列 apache と一致すると判断される
$pattern = '/apache/';
$match_num = preg_match($pattern, $subject, $matches);
var_dump($match_num); // int 1
var_dump($matches);   // array 0 => string 'apache' (length=6)

/*
 * 検索対象文字列は apache で始まっているためアンマッチと判断される
 */
$pattern = '/^apache/';
$match_num = preg_match($pattern, $subject, $matches);
var_dump($match_num); // int 0
var_dump($matches);   // array empty

/*
 * 検索対象文字列は php5 で始まっていないため一致すると判断される
 */
$pattern = '/^php5/';
$match_num = preg_match($pattern, $subject, $matches);
var_dump($match_num); // int 1
var_dump($matches);   // array 0 => string 'php5' (length=4)

行末の文字とマッチさせる(特殊文字 ‘ $ ‘)

行頭と一致させる正規表現が ‘ ^ ‘ であるのに対し、行末の文字とパターンマッチを行うには ‘ $ ‘ を使用します。

$subject = "php5 perl5 apache 1.3 apache2.2"; // 抽出対象文字列

/*
 * 行末が 'apache2.2' でないためマッチしない 
 */
$pattern = '/apache$/';
$match_num = preg_match($pattern, $subject, $matches);
var_dump($match_num); // int 0
var_dump($matches);   // array empty

/*
 * 行末が 'apache2.2' であるためマッチする 
 */
$pattern = '/apache2\.2$/';
$match_num = preg_match($pattern, $subject, $matches);
var_dump($match_num); // int 1
var_dump($matches);   // array 0 => string 'apache2.2' (length=9)

apache2.2 を aspache2\.2 としているのは、正規表現の特殊文字(メタキャラ)でドット( . )が使用されているのでエスケープさせる必要があるためです。

任意の一文字とマッチさせる(ドット)

ドット(.)をしようすると、任意の一文字としてパターンマッチされます。例えば 文字列 abcXdef 内の X を任意の一文字としてパターンマッチするには、以下のように /abc.def/ と記述します。

$subject = "abcXdef";
/*
 * マッチする
 */
$pattern = '/^abc.def/';
$match_num = preg_match($pattern, $subject, $matches);
var_dump($match_num); // int 1
var_dump($matches);   // array 0 => string 'abcXdef' (length=7)

$subject = "abcZdef";
/*
 * マッチする
 */
$pattern = '/^abc.def/';
$match_num = preg_match($pattern, $subject, $matches);
var_dump($match_num); // int 1
var_dump($matches);   // array 0 => string 'abcZdef' (length=7)

エスケープ

任意の一文字にマッチする特殊文字(.)は便利ですが、ドット自体をマッチさせたい場合は ( . )の前に( \ )を記述する必要があります。

// 円周率をパターンマッチさせる
$subject = '3.14';  // 円周率

/*
 * マッチする(ただし、例えば '3X14' でもマッチしてしまうので間違い)
 */
$pattern = '/3.14/';
$match_num = preg_match($pattern, $subject, $matches);
var_dump($match_num); // int 1
var_dump($matches);   // array array 0 => string '3.14' (length=4)

/*
 * マッチする(円周率のみマッチする)
 */
$pattern = '/3\.14/';
$match_num = preg_match($pattern, $subject, $matches);
var_dump($match_num); // int 1
var_dump($matches);   // array array 0 => string '3.14' (length=4)

直前文字の繰り返し(*、+)

// 以下のいずれの場合でもマッチする
$subject = "google";
//$subject = "goooooooooooooogle";
//$subject = "gooooooooooooooooooooooooooogle";

/*
 * マッチする
 */
$pattern = '/goo*gle/'; 
$match_num = preg_match($pattern, $subject, $matches);
var_dump($match_num); // int 1
var_dump($matches);   // array 0 => string 'google' (length=6)

/*
 * マッチする
 */
$pattern = '/goo+gle/';
$match_num = preg_match($pattern, $subject, $matches);
var_dump($match_num); // int 1
var_dump($matches);   // array 0 => string 'google' (length=6)

特殊文字(*) と (+) の違いは、 ( * ) は直前の文字が存在しなくともパターンマッチしますが、( + ) は直前の文字が存在しないとマッチしないということです。

// 抽出対象文字列
$subject = "gogle";

/*
 * マッチする
 */
$pattern = '/goo*gle/'; 
$match_num = preg_match($pattern, $subject, $matches);
var_dump($match_num); // int 1
var_dump($matches);   // array 0 => string 'gogle' (length=5)

/*
 * マッチしない
 */
$pattern = '/goo+gle/';
$match_num = preg_match($pattern, $subject, $matches);
var_dump($match_num); // int 0
var_dump($matches);   // array empty

直前の文字が存在するか、存在しないかわからない場合(特殊文字 ? )

下記は、スペース(1文字)の有無に関わらず、 いずれの場合でもパターンマッチさせる特殊文字( ? ) を使用した正規表現の例です。

// 検索対象文字列
$subject = "centos";    // マッチする(スペースなし)
//$subject = "cent os"; // マッチする(スペースあり)

$pattern = '/cent ?os/'; // スペースがあり、なしに関わらずマッチさせる
$match_num = preg_match($pattern, $subject, $matches);
var_dump($match_num); // int 1
var_dump($matches);   // array 0 => string 'centos/cent os' (length=6/7)

繰り返し回数の指定( {n}  {n,}  {n, m} )

特殊文字 ‘ { } ‘ を使用して、ある文字の繰り返し回数を指定してマッチングを行うことができます。

構文意味
{n}繰り返し回数が n 回
{n, }繰り返し回数が n 回以上
{n, m}繰り返し回数が n 回から m 回
// 検索対象文字列
$subject = "11111";     

$pattern = '/^1{4}/';      // 1 が 4回連続するのでマッチする
//$pattern = '/^1{5}/';    // 1 が 5回連続するのでマッチする
//$pattern = '/^1{6}/';    // 1 が 6回連続しないのでアンマッチ

$match_num = preg_match($pattern, $subject, $matches);
var_dump($match_num);      // int 1
var_dump($matches);        // array 0 => string '11111' (length=5)

$pattern = '/^1{5,}/';     // 1 が 5回以上連続するのでマッチする
//$pattern = '/^1{6,}/';   // 1 が 6回以上連続しないのでアンマッチ
$match_num = preg_match($pattern, $subject, $matches);
var_dump($match_num);      // int 1
var_dump($matches);        // array 0 => string '11111' (length=5)

$pattern = '/^1{7, 10}/';  // 1が7~10回の連続ではないのでアンマッチ
//$pattern = '/^1{1, 4}/'; // 1が1~4回の連続なの(を含む)でマッチする
//$pattern = '/^1{3, 7}/'; // 1が3~7回の連続なのでマッチする
$match_num = preg_match($pattern, $subject, $matches);
var_dump($match_num);      // int 1
var_dump($matches);        // array empty

マッチング対象文字を範囲指定する(特殊文字 ‘ [ ] ‘)

特殊文字 ‘ [] ‘ を使用して、文字がある範囲内の数値であるかをパターンマッチさせることができます。なお、行頭からの一致を示す特殊文字 ‘ ^ ‘ を ‘ [] ‘ 内で使用すると否定( NOT )を表すようになります。また、パターン文字を特定するのではなく、 [a-z] のようにハイフン( – )を使用して範囲指定を行うことができます。

構文意味
[0z]数値の 0 または 小文字の z 文字である場合にマッチ
[a-z]小文字の a ~ z 内の文字である場合にマッチ
[A-Z]大文字の A ~ Z 内の文字である場合にマッチ
[0-9]数値の 0 ~ 9 内の文字である場合にマッチ
[^A-Z]大文字の A ~ Z 以外の文字である場合にマッチ
[^a-zA-Z]小文字 a ~ z 大文字の A ~ Z 内の文字以外である場合にマッチ
// 検索対象文字列
$subject   = "0";   // マッチする
//$subject = "z"; // マッチする
//$subject = "Z"; // マッチしない

$pattern = '/[0z]/'; // 0 または z のパターンを抽出
$match_num = preg_match($pattern, $subject, $matches);
var_dump($match_num); 
var_dump($matches);   

// 検索対象文字列
$subject   = "a";   // マッチする
//$subject = "0"; // マッチする
//$subject = "A"; // マッチしない

$pattern = '/[a-z0-9]/'; // 小文字の a ~ z または 数字の 0 ~ 9 のパターンを抽出
$match_num = preg_match($pattern, $subject, $matches);
var_dump($match_num);
var_dump($matches);

// 検索対象文字列
$subject   = "j";   // マッチする
//$subject = "k";   // マッチしない

$pattern = '/[^a-ik-zA-Z0-9]/'; // 小文字の j 以外 && 大文字A ~ Z 以外 かつ 数値 0 ~ 9 以外を抽出
//$pattern = '/[j]/';           // 小文字の j を抽出(上記に近い。同じではないが。)
$match_num = preg_match($pattern, $subject, $matches);
var_dump($match_num);
var_dump($matches);

抽出パターンに複数の条件を設定する(特殊文字:パイプ ‘ | ‘)

パイプ( | )を使って複数の抽出条件を記述できます。 なお、条件は or (論理和)です。

// 検索対象文字列
$subject = "mac";     // マッチする
//$subject = "linux";   // マッチする
//$subject = "windows"; // マッチする
//$subject = "solaris"; // マッチしない

// 複数文字列を指定してパターン抽出する
$pattern = '/mac|linux|windows/';
$match_num = preg_match($pattern, $subject, $matches);
var_dump($match_num); 
var_dump($matches);   

グループ化(特殊文字 ‘ ( ) ‘ )

グループ化を使用してパターンの一部を複数の文字列でマッチングさせることができます。 以下は URI のスキーマ部分の抽出を行うサンプルになります。

// 検索対象文字列
$subject   = "http://";   // マッチする
//$subject = "https://";  // マッチする
//$subject = "ftp://";    // マッチする
//$subject = "file://";   // マッチする
//$subject = "http:";     // マッチしない('//' が足りない)
//$subject = "telnet://"; // マッチしない(未設定のスキーマである)

// グループ化して複数の抽出パターンを指定する。
// '/' は正規表現の囲み文字と区別するために '\' でエスケープする必要がある
$pattern = '/(https?|ftp|file):\/\//';
$match_num = preg_match($pattern, $subject, $matches);
var_dump($match_num); 
var_dump($matches);   

// '/' をエスケープしないと以下のエラーが警告が発生し、false がリターンされる

// Warning: preg_match() [function.preg-match]: Unknown modifier '/' in ・・・

PHP の正規表現(preg_replace)で改行の注意点メモ ”/\r\n|\r|\n/”は、’/\\\r\\\n|\\\r|\\\n/’ でなければいけなかった!?

PHPでは”” と” の違いは、”” だと変数などが中に書かれていると展開されるという扱い。

なのだけど、”/r/n”としたときと、’/r/n’とした時では挙動が違う

前者の”/r/n”は、文字コードで、確か「\r」はchr(13), 「\n」 => chr(10)
になってしまうんじゃないかな。

なので正規表現の中で”” を使っていて、しかも中でPHPが置き換える可能性のある文字は、
置き換えられてから関数で処理されてしまうから注意が必要

またこれはmysql やmyslqiの関数で、real_escape_string を使って
文字列を収納すると、「”」の方の”/r/n”、つまりchr(13)+chr(10)が、
普通の文字列の「’」の方の、’/r/n’になって保存されてしまう

文字列が二重引用符 (“) で括られた場合の話は公式の文字列 に話はある。

また、もしも上記のreal_escape_string(mysqli ならmysqli:: real_ escape_string
を使っちゃったら、nl2br 関数を使って処理すればいいや!なんて思っていても、
nl2br は文字コードのchr(13)+chr(10)、つまり”” の方の”/r/n” を
文字列の'<br>’ もしくは’<br />’ に置き換える関数で、ただの文字列となってしまっている
‘/r/n’ は置き換えられない。

置き換えられないならば、ereg_replace か、preg_replace で置き換えようと
想像がついたので置き換えようとした訳で、このブログを書いている。

まず、置き換えようとする時、”/r” や”/n” や”/r/n” は上記の様に
制御コードとなってしまうしので” でなくて ‘ にするのは良いとしても
エスケープシーケンス という方法を使わなければいけなくなる。

理由は/ という記号自身が文字や文字列である理由から逸脱(エスケープ)して、
しまう為、これを回避する方法が公式ページ(そのエスケープシーケンス )には

注意:

シングルクォートあるいはダブルクォートで囲まれた PHP の 文字列 の中では、バックスラッシュは特別な意味を表します。 そのため、正規表現 \\ を使用して \ とマッチさせたい場合は PHP のコード内では “\\\\” あるいは ‘\\\\’ と記述する必要があります。

と書いてある。

なので、よくサイトなどで、簡単な説明で
ereg_replace(“\n|\r|\r\n”,”<br>”,$string);
とかで動くんじゃ?と思ったけれど、これ動かなかった。

勿論正規表現をやめて
str_replace(array(“\r\n”,”\n”,”\r”),$br,$string);
とすれば動いた、けれどせっかくなので
preg_replace で動かそうと思った。

よく考えても何処にも答えがニアピンで載ってなくてよく分からなかったのだけれど、
/ ではエスケープシーケンス動作なので、これを消すには// かなと思ったけど、
そうすると多分、エスケープシーケンスを消すので、それは無かった事とされてしまう??w

あ、偶数でないと困るのかな・・・・、前後に // と正規表現をするから・・・
確かに上記の□枠の解釈だと/// と3つつけることになり、意味はあってそう

なんか、意味が具体的に書いてないからなんとも・・・・・・

本当によくわかってないけど・・・・まぁ・・・・ なんかをキャンセルしてると理解しようorz

ここ重要かもしれないけど、エスケープシーケンスをエスケープするのは’//’を前にくっつける??
これ、公式マニュアルに書いてない!!!???

なので’/n’ は’//’と’/n’ をくっつけた’///n’ でやっと文字列の「/n」を選んだ事になるみたい・・・
うーん、なんだか意味がわからないけど、これは公式の説明に載せて欲しいな・・・・

話は長くなったけれど、
結果を言えば
PHP の正規表現(preg_replace)で、改行を置き換えたい時は、
“/\r\n|\r|\n/”では動かないので、’/\\\r\\\n|\\\r|\\\n/’
にしなければいけない。

纏めると

改行を表すコードは
“/r” chr(13) これは’/r’ ではない!
“/n” chr(10) これは’/n’ ではない!
“/r/n” chr(13)+chr(10) これは’/r/n’ ではない!
※chr(10) とかchr(13) は確か・・・ そうだったと思う、このブログを書いている最中は
確かめてません・w・;

また正規表現で
文字列の「/r」つまり’/r’ を置き換えたい場合には、
エスケープシーケンスのエスケープをして
‘///r’ とする / は頭に2つ付けて // 合計3つで ///r となる。

同様に
/n => ///n
/r/n => ///r///n
となる。

これでOKみたい。

作った関数

//*********************************************************************************************************************************************************************************************************
// PHP の関数であるnl2br は文字コードの変換で、コードでなく文字に置き換えられた「\r(/r)」「\n(/n)」「\r\n(/r/n)」には使えないので、この関数で<br> もしくは、XHTML 準拠の <br /> に置き換える
function nl_string_2br($string,$is_xhtml=false){
if($is_xhtml==false){$br='<br />’;}else{$br='<br>’;}
// return str_replace(array(“\\r\\n”,”\\n”,”\\r”),$br,$string);
return preg_replace(‘/\\\r\\\n|\\\r|\\\n/’, $br, $string);

}

ネーミングセンスが微妙なので、使う場合には名前をつけなおそぅ(ぇ

あと、

// return str_replace(array(“\\r\\n”,”\\n”,”\\r”),$br,$string);

return preg_replace(‘/\\\r\\\n|\\\r|\\\n/’, $br, $string);

としてあるけど、str_replace が好みの人は

return str_replace(array(“\\r\\n”,”\\n”,”\\r”),$br,$string);

// return preg_replace(‘/\\\r\\\n|\\\r|\\\n/’, $br, $string);

としてね!

以上、長いメモでした<(_ _)>

追伸

公式マニュアルの定義済みの定数 に

PHP_EOL (string)このプラットフォームの行末文字。 PHP 4.3.10 および PHP 5.0.2 以降で利用可能。というのを見つけた。

プラットフォームによって変わるのかぁ・・・・・
うーん、フォームから入力、つまりブラウザから入力したって
プラットフォーム、つまりWebサーバーに依存するのかな

まぁいいや、どっちにしても/r と/n と/r/n 全てを処理した方が
無難そう。

コピペしたら多分、ブラウザからの入力に依存する気もする、
うん? やっぱブラウザの入力に依存するんじゃないか?v?

まぁ、いいや、多分そう使わないかな・・・・
サーバーの使う文字コードを調べるにしても、改行コードでは調べられないし。

一応追加のメモでしたぁ_(._.)_

追伸

先に書いた関数を使うより

// 文字コードでなく、文字として「\r(/r)」「\n(/n)」が存在する場合に、文字コードの改行に戻す
function br_string_2nl($string){
return str_replace(array(‘\r’,’\n’),array(“\r”,”\n”),$string);

}

こちらの関数を良く使う様になった(というか、先に書いた関数は使わなくなった^^;)

PHPで文字列を検索をする:strpos, strstr, preg_match

PHPで文字列を検索する主な関数として、strpos, strstr, preg_matchがあります。今回はそれぞれの関数の使い方を紹介します。

strposの使い方

strposは検索対象の文字列に検索する文字列が何文字目に存在するかを戻り値として返します。検索した文字列が見つからなかった場合はFALSEを返します。

strpos(検索対象の文字列, 検索する文字列)

以下は「’test@domain.com’」という文字列から「’@’」を検索した例です。

<?php
print strpos('test@domain.com', '@'); // 4

結果は「4」が出力されます。0から数えられるため、”@”が5文字目にあるということが確認できます。

strstrの使い方

strstrはマッチした文字列より後ろの文字列を戻り値として返します。検索した文字列が見つからなかった場合はFALSEを返します。

strstr(検索対象の文字列, 検索する文字列)

以下は「’test@domain.com’」という文字列から「’@’」を検索した例です。

<?php
print strstr('test@domain.com', '@'); // @domain.com

また、”@”より前の部分を表示したい場合は、以下のように第3引数にTRUEを渡します。

<?php
print strstr('test@domain.com', '@', TRUE); // test

preg_match()の使い方

preg_matchは正規表現による検索を行います。

preg_match( 正規表現 , 検索対象の文字列 [,マッチした文字列の配列])

検索対象文字列から正規表現にあてはまる文字列が存在するかチェックします。戻り値はマッチした文字列がある場合は「1」、ない場合は「0」を返します。

第3引数の配列には、正規表現にマッチした文字列が格納されます。第3引数以降は省略することができます。

<?php
if ( preg_match('/[^@]+$/', 'name@example.com', $matches) ) {
  print $matches[0]; // example.com
}

実行結果は、@より後ろの文字が格納されるため、「example.com」と表示されます。

定番のvar_dump

echo "<pre>";
var_dump($array);
echo "</pre>";

説明
1. var_dumpをそのまま実行すると成形されずにブラウザで表示されるため、preタグで挟んであげると綺麗に出力される

エラーログをコードに仕込んで任意のファイルに出力

error_log(print_r($array,true),"3","C:/xampp/log/debug.log");

説明
1. errer_log関数の第1引数に出力したい変数/文字列を入れる。
2. print_rの第2引数のtrueを渡してあげると配列が展開されてログに出力される。
3. error_log関数の第2引数に設定している”3”は任意のファイルに出力ということ
4. error_log関数の第3引数に設定しているパスは出力したい任意のファイルパスを入れること

このサイトに関するご意見・ご質問はこちらまで

この記事またはDrupalに関するご質問がございましたら、お気軽にお問い合わせください。

タイトルとURLをコピーしました