【2021/10/15 追記】
この記事は更新が停止されています。現在では筆者の思想が変化している面もありますので,過去の記事として参考程度にご覧ください。
番目指定は
0番目、1番目、2番目、…
というように0以上の整数とします。
想定しない値の例外処理はしていません。
strpos()
を使う
strpos() の第3引数 $offset
なんて滅多に出番ないと思ってたけど、こういう使い方ができるとは・・・
function strpos_n($str, $needle, $n = 0) {
$offset = 0;
$len = strlen($needle);
while ($n-- >= 0 && ($pos = strpos($str, $needle, $offset)) !== false) {
$offset = $pos + $len;
}
return $pos;
}
var_dump(strpos_n('He has a pencil that has a eraser on the top.', 'has', 1)); // int(21)
そのまま置換をしたい場合は substr_replace() に結果を渡してください。
マルチバイト対応版
バイトオフセットの代わりに文字オフセットで返します。
function mb_strpos_n($str, $needle, $n = 0, $encoding = null) {
if (func_num_args() < 4) {
$encoding = mb_internal_encoding();
}
$offset = 0;
$len = mb_strlen($needle, $encoding);
while ($n-- >= 0 && ($pos = mb_strpos($str, $needle, $offset, $encoding)) !== false) {
$offset = $pos + $len;
}
return $pos;
}
preg_match_all()
を使う
preg_match_all() のオプション PREG_OFFSET_CAPTURE
を利用した手法です。
回数が増えてきたりするとこちらの方が速いと思われます。
function strpos_n($str, $needle, $n = 0) {
$pattern = '/' . preg_quote($needle, '/') . '/';
return
preg_match_all($pattern, $str, $matches, PREG_OFFSET_CAPTURE) > $n ?
$matches[0][$n][1] :
false
;
}
こちらはマルチバイトに対応できません。