mb_str_replace (mb_replace)
何これ?
マルチバイト対応版の str_replace 関数です。 PHP 標準関数ではないため、サイトによって mb_str_replace、mb_replace 等と表記にゆれがありますがおそらく同じものです。
何に使うの?
日本語等(PHP が対応している言語なら何でも可)の文字列を一部置き換える場合に使います。
PHP に実装されている str_replace 関数はマルチバイト対応していないため、一部文字列が文字化けするかもしれません。 また、一部で行われている explode と join を使う方法等では思わぬところで文字が分断され、悲惨な結果になるかもしれません。
他に公開されているものとの違いは?
オリジナルの str_replace 関数は $search, $replace, $subject が配列対応していますが、 ほとんどの場所で公開されている mb_str_replace 関数は配列に対応していないようです。
ここで公開しているものは、$search, $replace, $subject の 3 引数については配列に対応していますので、 一気に置き換えることができます。 これにより、たとえば『ある文字セット(たとえば ISO-2022-JP)で使えないいわゆる機種依存文字(たとえば「㍼」「㍻」)を一般文字(たとえば「昭和」「平成」)に一気に置き換える』といったことが 1 呼び出しで行えます。
関数プロトタイプ
/**
* マルチバイト対応 str_replace
*
* @param mixed $search 検索文字列
* @param mixed $replace 置換文字列
* @param mixed $subject 対象文字列
* @param string $encoding 文字列のエンコーディング(省略: 内部エンコーディング)
*
* @return mixed subject 内の search を replace で置き換えた文字列
*
* @note この関数は配列に対応(search, replace, subject)しています。
*/
function mb_str_replace($search, $replace, $subject, $encoding = 'auto') { ... }
引数の最後に $encoding を追加し、マルチバイト対応関数としている以外は概ね (PHP 4 の) str_replace 関数と同じです。 $search, $replace, $subject 引数はそれぞれ配列とすることができます。 ただし、$seach および $replace が配列の場合の一部ケースで実行結果が異なります。詳しくは使用上の注意を参照してください。
使い方
関数を含んだファイルを require (include) して関数を呼び出すだけです。
<?php
require_once(dirname(__FILE__) . '/mb_str_replace.function.php');
$subject = '赤パジャマ青パジャマ黄パジャマ';
$search = 'パジャマ';
$replace = '信号';
$result = mb_str_replace($search, $replace, $subject);
var_dump($result);
?>
このサンプルの場合、「赤パジャマ青パジャマ黄パジャマ」内の「パジャマ」を「信号」に置き換えます。 つまり、赤信号青信号黄信号 となります。
※実際には、第 4 引数 ($encoding) に適切なエンコードを指定してください。 内部コードとエンコードが同一の場合は省略してもかまいません。
ライセンス
この関数は(修正済み) BSD ライセンスで提供します。 原作者表記のある限り、自由に利用いただいて結構です。
メンテナ
この関数は、HiNa がメンテナンスしていますが、動作等について保証するものではありません。 また、ライセンスは上述の通りで、利用時に報告する必要は全くありませんが一言いってもらえると大変喜びます。
なお、この関数についての連絡にはメールを送るよりも、日記のコメント機能(リンク先は初出時の日記エントリ) を利用したほうが確実に目に入ります。 メールはご他聞に漏れず、spam メールであふれています。
ダウンロード
この後の項目にソースコードがべた張りしてありますので、そちらをコピー&ペーストいただいても同じものが得られますが、どうしてもダウンロードしたい場合は、こちらをご利用ください。
ダウンロード (tar.gz / 1.02kB / SHA1SUM: a2baede0c5db1f5de3f3325e2f878cf4ee3a7ac8)
ソースコード
<?php
// THIS FILE WRITTEN IN UTF-8, Japanese.
/**
* マルチバイト対応 str_replace
*
* @version Release 2
* @author HiNa (hina@bouhime.com)
* @copyright Copyright (C) 2006-2007 by HiNa(hina@bouhime.com).
*/
if(! function_exists('mb_str_replace')) {
/**
* マルチバイト対応 str_replace
*
* @param mixed $search 検索文字列
* @param mixed $replace 置換文字列
* @param mixed $subject 対象文字列
* @param string $encoding 文字列のエンコーディング(省略: 内部エンコーディング)
*
* @return mixed subject 内の search を replace で置き換えた文字列
*
* @note この関数は配列に対応(search, replace, subject)しています。
*/
function mb_str_replace($search, $replace, $subject, $encoding = 'auto') {
if(! is_array($search)) {
$search = array($search);
}
if(! is_array($replace)) {
$replace = array($replace);
}
if(strtolower($encoding) === 'auto') {
$encoding = mb_internal_encoding();
}
if(is_array($subject)) {
$result = array();
foreach($subject as $key => $val) {
$result[$key] = mb_str_replace($search, $replace, $val, $encoding);
}
return $result;
}
$currentpos = 0;
while(true) {
$index = -1;
$minpos = -1;
foreach($search as $key => $find) {
if($find == '') {
continue;
}
$findpos = mb_strpos($subject, $find, $currentpos, $encoding);
if($findpos !== false) {
if($minpos < 0 || $findpos < $minpos) {
$minpos = $findpos;
$index = $key;
}
}
}
if($minpos < 0) {
break;
}
$r = array_key_exists($index, $replace) ? $replace[$index] : '';
$subject = sprintf('%s%s%s',
mb_substr($subject, 0, $minpos, $encoding),
$r,
mb_substr(
$subject,
$minpos + mb_strlen($search[$index], $encoding),
mb_strlen($subject, $encoding),
$encoding
)
);
$currentpos = $minpos + mb_strlen($r, $encoding);
}
return $subject;
}
}
?>
使用上の注意
mb_str_replace 関数は PHP 4 の str_replace と似た挙動を示しますが、$search および $replace が配列の場合の挙動が一部異なります。 完全互換ではありませんので注意して利用してください。
テストコード:
<?php
$subject = 'hogefuga';
$table = array('hoge' => 'foo',
'fuga' => 'bar',
'piyo' => 'baz',
'foo' => '***',
'bar' => '+++',
'baz' => '---');
$functions = array('str_replace', 'mb_str_replace');
foreach($functions as $f) {
$result = $f(array_keys($table), array_values($table), $subject);
printf("%s: %s\n", $f, $result);
}
?>
実行結果:
str_replace: ***+++
mb_str_replace: foobar
※CentOS 5.3(x86-64)上の PHP 5.1.6 の実行結果
このように結果が異なる場合があります。(上のテストコードは、str_replace および mb_str_replace に簡単な置換を行わせています。置換ルールは $table に書いてあります)
PHP のソースを読んだ訳ではありませんが、挙動から str_replace は次のような操作で置換をおこなっていると考えられます。(擬似コードのため動作しません)
<?pseudo-php
function str_replace_($search, $replace, $subject) {
// $subject が配列ならそれぞれの要素に対して個別に処理する
if(is_array($subject)) {
$result = array();
foreach($subject as $k => $s) {
$result[$k] = str_replace_($search, $replace, $s); // 個別処理(再帰)
}
return $s;
}
// $search (および $replace) が配列なら、それぞれの要素を使って置き換える
// 例: $search = array('a', 'b'); $replace = array('b', 'c'); $subject = 'abc'; ならば:
// 1. $subject の中から 'a' を探し、存在したら 'b' に置き換える:
// [$subject = 'abc'] => [$subject = 'bbc']
// 2. $subject の中から 'b' を探し、存在したら 'c' に置き換える:
// [$subject = 'bbc'] => [$subject = 'ccc']
// 3. $subject を関数の戻り値とする
if(is_array($search)) {
foreach($search as $s) {
$r = ($s に対応する値を取得);
$subject = str_replace_($s, $r, $subject); // 個別処理(再帰)
}
return $subject;
}
return ($subject 中の $search を $replace に置き換える);
}
?>
一方、mb_str_replace は「置換された文字列は二度と置換しない」ルールになっています。(「"hoge" から置き換えられた "foo"」には「"foo" から "***" に置き換える」ルールは適用されません。mb_str_replace 関数内の $currentpos に注目すると良いと思います)
この挙動は、mb_str_replace 実装者である HiNa が「この方が(プログラマにとって)より自然だ」と考えることに由来します。 PHP 標準関数と同じ挙動を希望する場合は、$search および $replace を配列で指定せず、複数回呼び出してください。