マルチバイトのstr_replace(mb_str_replace)がphpに無いのでそれらしいものを作りました。
mb_str_replace_emulate()の使い方は、エンコードの指定を除いて、str_replaceとたぶんほぼ同じです。mb_str_replace_emulate()でパラメータを文字列にしてmb_str_replace_emulate_sub()を呼び出していますので、パラメータに配列を渡さないのであればmb_str_replace_emulate_sub()を直接使えます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
/** * マルチバイトstr_replace * 使い方はstr_replaceとだいたい同じ * * @param string|array $search * @param string|array $replace * @param string|array $subject * @param string|bool $encoding * @param int $count * @return array|string */ function mb_str_replace_emulate($search, $replace, $subject, $encoding = false, &$count = 0) { //パラメータが配列の時の処理に合わせる $searches = (is_array($search)) ? $search : array($search); $replaces = (is_array($replace)) ? $replace : array($replace); //配列の数を合わせる if (count($searches) > count($replaces)) { $pad = (is_string($replace)) ? $replace : ""; $replaces = array_pad($replaces, count($searches), $pad); } if (is_array($subject)) { //与える文字列が配列の場合 $results = array(); foreach ($subject as $i => $subject_str) { foreach ($searches as $k => $search_str) { $replace_str = $replaces[$k]; $results[$i] = mb_str_replace_emulate_sub($search_str, $replace_str, $subject_str, $encoding, $count); } } return $results; }else{ //文字列が一つの場合 $result = $subject; foreach ($searches as $k => $search_str) { $replace_str = $replaces[$k]; $result = mb_str_replace_emulate_sub($search_str, $replace_str, $result, $encoding, $count); } return $result; } } /** * @param string $search * @param string $replace * @param string $subject * @param string|bool $encoding * @param int $count * @return string */ function mb_str_replace_emulate_sub($search, $replace, $subject, $encoding = false, &$count = 0) { //省略されていたら内部エンコード if (!$encoding) { $encoding = mb_internal_encoding(); } //よく分からないときは触らぬ神にたたり無し if (!mb_check_encoding($search, $encoding) || !mb_check_encoding($replace, $encoding) || !mb_check_encoding($subject, $encoding)) { return $subject; } //$searchが1文字以上でなければ戻る if (!mb_strlen($search, $encoding) || !mb_strlen($subject, $encoding)) { return $subject; } //2段階処理のため、文字列に含まれない中間マークを作成 $mark_num = 0; do { $mark = "#{$mark_num}%"; $mark_num++; } while (mb_strpos($search, $mark, 0, $encoding) !== false || mb_strpos($replace, $mark, 0, $encoding) !== false || mb_strpos($subject, $mark, 0, $encoding) !== false); //$replaceに$searchが含まれていると無限ループになるので2段階で置換する $reps = array($search => $mark, $mark => $replace); foreach ($reps as $s => $r) { $s_len = mb_strlen($s, $encoding); $s_pos = mb_strpos($subject, $s, 0, $encoding); //$sを残らず$rに入れ替える while ($s_pos !== false) { $all_len = mb_strlen($subject, $encoding); $before_content = ($s_pos > 0) ? mb_substr($subject, 0, $s_pos, $encoding) : ""; $after_len = $all_len - ($s_pos + $s_len); //php5.4.8以前ではafter_lenにnullが使えない $after_content = mb_substr($subject, $s_pos + $s_len, $after_len, $encoding); $subject = "{$before_content}{$r}{$after_content}"; $count++; $s_pos = mb_strpos($subject, $s, 0, $encoding); } } return $subject; } |
ご参考になるかもしれないポイントは、
・繰り返し処理の構文
foreach()、do…while()、while()
・マルチバイト関数
mb_internal_encoding()、mb_check_encoding()、
mb_strlen()、mb_strpos()、mb_substr()
・パラメータの参照渡し
・中間マークで文字列処理