【2021/10/15 追記】
この記事は更新が停止されています。現在では筆者の思想が変化している面もありますので,過去の記事として参考程度にご覧ください。
出来るだけもとの関数の挙動に近づけています。
basename()
について
PHP4.4.9まではNULLバイトを正しく処理できませんでしたが、
PHP5.0.0以降はバイナリセーフになりました。
(徳丸さんよりご指摘を頂きました)
但し、 setlocale()
でロケールを正しく設定していることが前提になります。
エンコーディングが壊れていてもそのまま処理します。
マルチバイト対応 explode()
explode() を使えば問題ない。
function mb_explode($delimiter, $string, $limit = -1, $encoding = null) {
$tmp = mb_regex_encoding();
mb_regex_encoding(func_num_args() > 3 ? $encoding : mb_internal_encoding());
$delimiter = mb_ereg_replace('[.\\\\+*?\\[^$(){}|]', '\\\\0', $delimiter);
$ret = mb_split($delimiter, $string, $limit);
mb_regex_encoding($tmp);
return $ret;
}
エンコーディングが壊れていてもそのまま処理します。
マルチバイト対応 str_split()
function str_split_utf8($string, $split_length = 1) {
switch (true) {
case ($split_length = (int)$split_length) < 1:
return false;
case !preg_match_all("/.{{$split_length}}|.++|\\A\\z/us", $string, $matches):
return null;
default:
return $matches[0];
}
}
長さ指定が間違っているときは FALSE を返します。
エンコーディングが壊れているときは NULL を返します。
function mb_str_split($string, $split_length = 1, $encoding = null) {
if ($split_length < 1) {
return false;
}
if (func_num_args() < 3) {
$encoding = mb_internal_encoding();
}
$ret = array();
$len = mb_strlen($string, $encoding);
for ($i = 0; $i < $len; $i += $split_length) {
$ret[] = mb_substr($string, $i, $split_length, $encoding);
}
if (!$ret) {
$ret[] = '';
}
return $ret;
}
長さ指定が間違っているときは FALSE を返します。
エンコーディングが壊れていてもそのまま処理します。
マルチバイト対応 trim()
function trim_utf8($str, $charlist = " \t\n\r\0\x0B ") {
$charlist = str_replace('..', '-', addcslashes($charlist, "^-:]\0\\/"));
return preg_replace("/\\A[{$charlist}]++|[{$charlist}]++\\z/u", '', $str);
}
エンコーディングが壊れているときには NULL を返します。
function mb_trim($str, $charlist = " \t\n\r\0\x0B ", $encoding = null) {
$tmp = mb_regex_encoding();
mb_regex_encoding(func_num_args() > 2 ? $encoding : mb_internal_encoding());
$charlist = mb_ereg_replace('[\\[\\]^-]', '\\\\0', $charlist);
$charlist = mb_ereg_replace('\\.{2}', '-', $charlist);
$ret = mb_ereg_replace("\\A[{$charlist}]++|[{$charlist}]++\\z", '', $str);
mb_regex_encoding($tmp);
return $ret;
}
エンコーディングが壊れていてもそのまま処理します。
ltrim()
, rtrim()
もこんな感じでどうぞ。
マルチバイト対応 wordwrap()
想像以上に処理が大変だったので今回はギブアップ(汗)
マニュアルのコメント欄に投稿されているものもどれも再現性が微妙なものばかりで、みなさん苦戦されている様子。
いろいろ試してみた結果、 Smarty の mb_wordwrap()
が一番良さげだったので紹介しておきます。
https://github.com/Jamesking56/Smarty-PHP/blob/master/plugins/shared.mb_wordwrap.php
もっと簡単に書けたらいいのになぁ・・・
マルチバイト対応 str_replace()
str_replace() を使えば問題ない。
function mb_str_replace($search, $replace, $subject, $encoding = null) {
$tmp = mb_regex_encoding();
mb_regex_encoding(func_num_args() > 3 ? $encoding : mb_internal_encoding());
foreach ((array)$search as $i => $s) {
if (!is_array($replace)) {
$r = $replace;
} elseif (isset($replace[$i])) {
$r = $replace[$i];
} else {
$r = '';
}
$s = mb_ereg_replace('[.\\\\+*?\\[^$(){}|]', '\\\\0', $s);
$subject = mb_ereg_replace($s, $r, $subject);
}
mb_regex_encoding($tmp);
return $subject;
}
エンコーディングが壊れていてもそのまま処理します。
マルチバイト対応 strtr()
string strtr_utf8 ( string $str , string $from , string $to )
string strtr_utf8 ( string $str , array $replace_pairs )
function strtr_utf8() {
if (func_num_args() < 3) {
list($str, $replace_pairs) = func_get_args();
} else {
list($str, $from, $to) = func_get_args();
$from = preg_split('//u', $from, -1, PREG_SPLIT_NO_EMPTY);
$to = preg_split('//u', $to, -1, PREG_SPLIT_NO_EMPTY);
$replace_pairs = array();
foreach ($from as $i => $f) {
if (!isset($to[$i])) {
break;
}
$replace_pairs[$f] = $to[$i];
}
}
return strtr($str, $replace_pairs);
}
エンコーディングが壊れていてもそのまま処理します。
string mb_strtr ( string $str , string $from , string $to [, string $encoding] )
string mb_strtr ( string $str , array $replace_pairs [, string $encoding] )
<?php
function mb_strtr() {
$args = func_get_args();
if (!is_array($args[1])) {
list($str, $from, $to) = $args;
$encoding = isset($args[3]) ? $args[3] : mb_internal_encoding();
$replace_pairs = array();
$len = mb_strlen($from, $encoding);
for ($i =0; $i < $len; $i++) {
$k = mb_substr($from, $i, 1, $encoding);
$v = mb_substr($to, $i, 1, $encoding);
$replace_pairs[$k] = $v;
}
return $replace_pairs ? mb_strtr($str, $replace_pairs, $encoding) : $str;
}
list($str, $replace_pairs) = $args;
$tmp = mb_regex_encoding();
mb_regex_encoding(isset($args[2]) ? $args[2] : mb_internal_encoding());
uksort($replace_pairs, function ($a, $b) {
return strlen($b) - strlen($a);
});
$from = $to = array();
foreach ($replace_pairs as $f => $t) {
if ($f !== '') {
$from[] = '(' . mb_ereg_replace('[.\\\\+*?\\[^$(){}|]', '\\\\0', $f) . ')';
$to[] = $t;
}
}
$pattern = implode('|', $from);
$ret = mb_ereg_replace_callback($pattern, function ($from) use ($to) {
foreach ($to as $i => $t) {
if ($from[$i + 1] !== '') {
return $t;
}
}
}, $str);
mb_regex_encoding($tmp);
return $ret;
}
エンコーディングが壊れていてもそのまま処理します。
PHP5.4.1 以降のみ対応。
備考
なお文字列置換関数に関して、動作の軽い順に
-
strtr()
(引数3つ) -
str_replace()
(配列を含まない) -
str_replace()
(配列を含む) -
strtr()
(引数2つ)
――超えられない壁――
-
strtr_utf8()
(引数2つ) -
strtr_utf8()
(引数3つ)
――超えられない壁――
-
mb_str_replace()
(配列を含まない) -
mb_strtr()
(引数2つ) -
mb_str_replace()
(配列を含む) -
mb_strtr()
(引数3つ)
だいたいこんな感じのパフォーマンス順位になると思います。
正確なことは検証してないので分かりませんが。