ラムネグから一言:寝る前に読むとくだらなすぎて逆に寝れると好評なすごい適当なブログをこっちではじめてます.
phpで文字列を置換するのはpreg_replace!ですよね。ただpreg_replaceでは基本的にはぜんぶおんなじ文字列にしか置換できないはず。(やり方あるのかな?)
例えば長い文字列の中で置換対象の文字列が見つかるたびに、一つずつインクリメントした連番に置換したいような場合ってどうすればいいんでしょう。
ここではphpでpreg_replaceを使って連番や通し番号をつけて置換する方法を紹介します。
preg_replace_callback関数を使う
preg_replace関数でも昔は「/e」をつけると連番や通し番号をつけられたようなんですが、PHPのpreg_replaceの説明を見るとphpバージョン5くらいから「/e」っていうのが非推奨になったみたいです。
実際に「/e」で連番付けたわけじゃないので今どうなのかはわかりませんが、とりあえず安心のpreg_replace_callback関数を使って連番に置換していきましょう。
- 「/e」ってなんなん?
-
preg_replaceするときって第一引数に検索対象の文字列(だいたいは正規表現)が入りますよね。
そのとき「/…/u」みたいにスラッシュで囲むと思うんですが、この「/u」の部分に「/e」て書くと第二引数に数式が使えるようになるみたいです。
ちなみに「/u」は文字コードがUTF-8だよっていう指定です。なくてもOKだと思います。
preg_replace_callbackの使い方
preg_replace_callbackは第二引数が関数になってるだけのpreg_replace関数です。ラクチンに使えちゃいます。
例:「abc」が見つかるたび「abc-〇〇」と連番をつける置換
$num = 0;
$content = preg_replace_callback(
'/abc/u',
function($matches) use(&$num){
return $matches[0] . '-' . $num++;
},
$content
);
置換前「abc def abc kio aaa abc」
結果「abc-0 def abc-1 kio aaa abc-2」
こんな感じ。preg_replace_callbackの引数は、
- 第一引数:検索文字列(正規表現OK)
- 第二引数:関数(例では無名関数を使ってます)
- 第三引数:検索対象の文字列
戻り値が置換後の検索文字列なので「$content」に代入。ここらへんはpreg_replaceと全く同じですね。
第二引数の関数あたりが独特なのでちょっと説明しておくと、ここは例みたいな無名関数でもいいし、どこかほかの場所に宣言した関数をいれてもOKです。この関数内でreturnした文字列に置換されます。
第二引数は$matchesという引数を勝手にとってくれて、この中の$matches[0]には見つかった検索対象の文字列(例だとabc)が入っています。
preg_replace_callbackでは文字列が見つかるたびにこの第二引数の関数が呼ばれるので、abcが見つかるたびにabcに$numの値が追加されたものに置換されていきます。
- use()ってなんなん?
-
例の中でuseっていうのを使っています。
PHPでは無名関数の中で親関数の変数を使うときにこのuse宣言が必要になります。
今回は通し番号をふるため、親関数の方で$numを宣言しているので無名関数内でこの$numを使うにはuseが必要になるんです。
さらにいうとそのあとにある「&」マークですが、これがないと参照渡しにならないので無名関数内でいくら数字をプラス(インクリメント)しても次に無名関数が呼ばれるときはインクリメント前の数字に戻ってしまいます。
$matchesの中身はなんなの?
$matches[0]には見つかった検索文字列が入ってるてことだったんですが、なら配列の他の中には何が入ってるんでしょうか。
preg_replaceなどPHPの文字列をどうにかこうにかする関数は、正規表現中に()を使うことができます。この()はパターン宣言ができるやり方で例えば「$1」とかって書いてあとから()でくくったパターンを使いまわせるんです。
$matchesの[1]や[2]にはこのパターンが格納されています。
ちょっと見てみましょう。
例:「abc」が見つかるたび「ab-〇〇-c」と通し番号をつける
$num = 0;
$content = preg_replace_callback(
'/(ab)(c)/u',
function($matches) use(&$num){
$result = $matches[1] . '-' . $num . '-' . $matches[2];
$num++;
return $result;
},
$content
);
置換前「abc def abc kio aaa abc」
結果「ab-0-c def ab-1-c kio aaa ab-2-c」
この例で$matches[1]には最初の()でパターンにした「ab」が入り、$matches[2]には二つ目の()でパターン化した「c」が格納されています。
あとは「ab」と「c」で$numの値をはさみこんでやってreturnすればOK!
preg_replace_callbackまとめ
PHPのpreg_replace_callback関数、連番や通し番号をつけて置換できるすごいやつです。
ちなみに連番やら通し番号じゃなくっても、このpreg_replace_callback関数を使えば例えばかなり柔軟に置換ができるようになるのでどんどん使ってみてくださいね。
【おしらせ、というか完全なる宣伝】
文体がもうぜんぜん適当すぎてあれだけどものすごい自由に書いてるブログ「檸檬だくだく」もよろしく.寝る前に読める恐ろしくくだらないやつです.
こんなにも一ミリも目を引かれないタイトルを取り扱ってます: ココア20g / ハイチュウとかってさ / なぜ米と小麦を食べようと思ったのかの謎 /