読者です 読者をやめる 読者になる 読者になる

アナログCPU:5108843109

ゲームと音楽とプログラミング(酒と女とロックンロールのノリで)

文字列置換

PHP 文字列処理 置換 速度検証

ある文字列を別の文字列に置換したい場合、
str_replace や preg_replace を使用する。

とりあえずマニュアルは以下。

参考:str_replace - php.net
http://php.net/manual/ja/function.str-replace.php
参考:preg_replace - php.net
http://php.net/manual/ja/function.preg-replace.php

str_replace

固定の文字列を別の文字列に置換する。

$text = "置換前の文字列";
print str_replace("前", "後", $text); // 「置換後の文字列」と表示される

preg_replace

正規表現で指定した文字列を別の文字列に置換する。

$text = "置換前の文字列";
print preg_replace("/前/", "後", $text); // 「置換後の文字列」と表示される

置換前後の文字列や正規表現複数指定可能

str_replace も preg_replace も、
置換前後の文字列は配列形式で複数指定することができる。

以下の例は str_replace で記載していますが、preg_replace でも同じです。

  • 要素が同数の場合:対応する要素に置換
$text = "hoge_fuga_piyo";
print str_replace(array("hoge", "fuga", "piyo"), array("ほげ", "ふが", "ぴよ"), $text);
// 「ほげ_ふが_ぴよ」と表示される
$text = "hoge_fuga_piyo";
// 数値がキーの連想配列であっても並び順通りに対応される
print str_replace(array(1=>"hoge", 2=>"fuga", 3=>"piyo"), array(3=>"ほげ", 1=>"ふが", 2=>"ぴよ"), $text);
// これも「ほげ_ふが_ぴよ」と表示される
  • 置換前の要素が複数、置換後の要素が1つの場合:すべて置換後の文字列に置換
$text = "hoge_fuga_piyo";
print str_replace(array("hoge", "fuga", "piyo"), "*", $text);
// 「*_*_*」と表示される
  • 置換前も置換後も複数だが、置換後の方が少ない場合:足りない分は空文字に置換される
$text = "hoge_fuga_piyo";
print str_replace(array("hoge", "fuga", "piyo"), array("ほげ", "ふが"), $text)
// 「ほげ_ふが_」と表示される
  • 置換前も置換後も複数だが、置換後の方が多い場合:余る分は無視される
$text = "hoge_fuga_piyo";
print str_replace(array("hoge", "fuga"), array("ほげ", "ふが", "ぴよ"), $text)
// 「ほげ_ふが_piyo」と表示される
  • 置換前の要素が配列で1つ、置換後の要素が複数の場合:余る分は無視される
$text = "hoge_fuga_piyo";
print str_replace(array("hoge"), array("ほげ", "ふが", "ぴよ"), $text)
// 「ほげ_fuga_piyo」と表示される
  • 置換前の要素が非配列で1つ、置換後の要素が複数の場合:置換後の要素が文字列化(つまり"Array")されて置換される
$text = "hoge_fuga_piyo";
print str_replace("hoge", array("ほげ", "ふが"), $text);
// 「Array_fuga_piyo」と表示される

str_replace で複数置換する際の処理順に注意

参考:[PHP]str_replaceで複数置換する際に気をつけること - PHP ARCHIVE
http://php-archive.net/php/php-str-replace/

置換する際は、配列で指定された順に置換されていきます。

$text = "abcde";
print str_replace(array("ab", "bc", "dc"), "cd", $text);
// 「ccdde」と表示される

見た通り
「abcde」の「ab」「bc」「dc」をすべて「cd」に置換する
というコードですが、以下のように処理されています。

①「ab→cd」の置換:「cdcde」になる
②「bc→cd」の置換:①で「bc」はなくなったので何もしない
③「dc→cd」の置換:①で「dc」ができたので「ccdde」になる

どう処理したいかによりますが、
場合によって処理順を調整したり、preg_replace を使用するなど、
よく考えてコーディングする必要があります。

PHPではないのですが、
改行コードをCRLFに統一するのに
「CR→CRLF」「LF→CRLF」という処理を入れたら、
 「CR CRLF LF」
  ↓CRをCRLFに置換
 「CRLF CRLF LF LF」
  ↓LFをCRLFに置換
 「CR CRLF CR CRLF CRLF CRLF」
となってしまうというバグを生みだしていたことが今日発覚しました…。
(ちなみに、CRLFである必要はない箇所だったので、
 CRLF→LF、CR→LF とLFに統一することで解決としました)

str_replace VS preg_replace 速度検証

以下、①~④のコードをそれぞれ1万回繰り返すのにかかった時間で速度検証してみました。
(③④はコードとしては等価ではありませんが)

$text_1 = "hoge_fuga";
$text_2 = "hoge_fuga_hage_hoge";

//①
str_replace"hoge", "*", $text_1);
//②
preg_replace("/hoge/", "*", $text_1);


//③
str_replace(array("hoge", "hage"), "*", $text_2);
//④
preg_replace("/h.ge/", "*", $text_2);

① VS ②

試行回数 ①(ミリ秒) ②(ミリ秒) ②÷①
1 5.269 9.722 1.85
2 5.577 9.743 1.75
3 5.271 9.857 1.87
4 5.569 9.771 1.75
5 5.277 9.715 1.84

③ VS ④

試行回数 ③(ミリ秒) ④(ミリ秒) ④÷③
1 10.788 11.676 1.08
2 10.780 11.752 1.09
3 10.738 11.707 1.09
4 10.763 11.744 1.09
5 10.751 11.673 1.09

ということで、一般に言われているとおり、str_replace の方が高速です。
文章量や置換内容によって色々と変わってくるでしょうが(③④なんかほぼ変わりないですし)
str_replace で充分であればその方がよい可能性が高そうです。

もしくは、その他の置換関数もありますので、場合によってはそちらを使用すべきケースもありそうです。

参考:PHPで改行コードを統一する関数: CRLF, CR, LF が混在してる文字列を LF に変換するなど - Qiita
http://qiita.com/suin/items/cbbbe8844fd734fa20e2