ホームページ > php教程 > php手册 > discuz と ecshop インターセプト文字列関数の PHP バージョンを比較する

discuz と ecshop インターセプト文字列関数の PHP バージョンを比較する

WBOY
リリース: 2016-06-13 11:58:12
オリジナル
881 人が閲覧しました

次に、最初にソース コードと 2 つのバージョンの関数の簡単なテストを示します。最後に、より実用的な文字列インターセプト関数を示します。ここで説明する文字列インターセプトの問題はすべて、UTF-8 でエンコードされた中国語文字列に関するものであることに注意してください。
ディスクバージョン

コードをコピー コードは次のとおりです:


/**
* [discuz] mb_substr やその他の拡張機能がインストールされていない PHP に基づくインターセプト文字列。中国語文字がインターセプトされた場合、2 文字として計算されます。
* @param $string インターセプトされる文字列
* @ param $length to be インターセプトされた文字数
* @param $dot 切り捨てられた部分の終了文字列を置き換えます
* @return インターセプトされた文字列を返します
* /
function Cutstr($string, $length, $dot = '...') {
// 文字列がインターセプトする長さより短い場合は、直接戻ります
//ここで strlen を使用して文字を取得します。 文字列の長さには大きな欠点があります。たとえば、文字列「Happy New Year」
// から 4 つの中国語文字をインターセプトしたい場合は、これら 4 つの中国語のバイト数を知る必要があります。それ以外の場合、返される文字列は「Happy New Year...」になります。
if (strlen($string) <= $length) {
return $string
}
// 変換元の文字列の htmlspecialchars
$pre = chr(1);
$string = str_replace (array ('&', '"', '<', '>' )、配列 ($pre . '&' . $end, $pre . '"' . $end, $pre . '<' . $end, $pre . '>' . $end ) , $string );
$strcut = ''; // 初期化戻り値
// utf-8エンコードの場合(この判定はちょっと不完全なのでutf8の可能性があります)
if (strto lower) ( CHARSET ) == 'utf-8') {
//初期連続ループポインタ $n、最後の文字数 $tn、インターセプトされた文字数 $noc
$n = $tn = $noc = 0;
while ( $n < strlen ( $string ) ) {
$t = ord ( $string [$n] );
if ($t == 9 || $t = = 10 || (32 <= $t && $t <= 126)) {
// 英語の半角記号などの場合は $n ポインタが 1 桁戻り、 $tn の最後の単語は 1 桁です
$tn = 1;
$noc ;
} elseif (194 <= $t && $t <= 223)
// 2 バイト文字の場合、$n ポインタは 2 ビット戻り、$tn の最後のワードは 2 ビットになります
$tn = 2; ;
$noc = 2;
} elseif (224 <= $t && $t <= 239) {
/ / 3 バイトの場合 (中国語の単語として理解できます) $n は 3 桁シフトされ、$tn の最後のワードは 3 桁になります。
$n = 3;
$noc = 2; <= $t && $t <= 247) {
$tn = 4;
$noc = 2; && $t <= 251) {
$tn = 5;
$noc = 2;
} elseif ($ t == 252 || $t == 253) {
$tn = 6;
$n = 2;
} else {
}
//取得する数を超えた場合の連続ループの
if ($noc >= $length) {
break;
}
}
// ここは、 $dot を追加する準備中の最後の単語
if ($noc > $length) {
$n -= $tn;
}
$strcut = substr ( $ string, 0, $n );
} else {
// utf-8 ではない全角エンコーディングは 2 ビットだけシフトバックされます
for ($i = 0; $i $strcut .= ord ( $string [$i] ) > $string [$i] : $string [$i];
// 元の htmlspecialchars を復元します
$strcut = str_replace( array ($pre . '&' . $end, $pre . '"' . $end, $pre . '<' . $ end, $pre . '>$end )、array ('&'、'"'、'<'、'>' )、$strcut );
$pos = strrpos ( 1 ) );
if ($pos !== false) {
$strcut = substr ( $strcut, 0, $pos );
return $strcut ;最後に、インターセプトを $dot 出力に追加します
}


discuz バージョンの最大の欠陥は、strlen を使用して元の文字列の長さを取得し、それを受信長パラメーターで使用することです。 UTF-8 の中国語文字のバイト数は固定されていないため、次のジレンマに直面します。4 つの中国語文字をインターセプトしたい場合、どのくらいのインターセプト長を指定する必要がありますか? 8バイトですか、それとも12バイトですか? 。 。 。これは予測不可能であり、次のテスト結果からわかるように、この問題が原因で discuz の Cutstr には実際にはバグがあります:



Copy code

コードは次のとおりです:


$str1 = "貧乏になりたい";
echo my_cutstr($str1, 10, "...")."n";出力: 貧乏になりたいという願望 Qianmile... [これはバグです。原因を考えてください。 ]
echo my_cutstr($str1, 15, "...")."n"; // 出力: Yuqiongqianlimu



上記のバグの理由は、 Cutstr 関数は、文字をインターセプトするときに、中国語の文字は 2 文字としてカウントされるため、5 つの中国語の文字は 10 文字となり、元の文字列の長さは 15 バイトであるため、cutstr は 15 文字の文字列から「正常に」インターセプトされたとみなします。 10文字に「しっぽ」を追加しました。このバグを解決するには、返された部分文字列が元の文字列と同じかどうかを確認するだけです。同じである場合は、「末尾」を追加しないでください。

ecshop バージョン

コードをコピー

コードは次のとおりです:


/**
* [ecshop] PHP の mb_substr および iconv_substr 拡張機能に基づいて、これら 2 つの拡張機能は文字列をインターセプトするために使用されます。
* この関数は、utf-8 でエンコードされた中国語文字列にのみ適用されます。 。
*
* @param $str 元の文字列
* @param $length インターセプトされた文字数
* @param $append 終了文字列を切り詰められた部分に置き換えます
* @return Returnインターセプトされた文字列
*/
function sub_str($str, $length = 0, $append = '...') {
$str =trim($str);
$strlength = strlen($str);
if ($length == 0 || $length >= $strlength) {
return $str>} elseif ($length < 0) {
$length = $strlength $length;
if ($length $length = $strlength;
}
}
if ( function_exists( 'mb_substr') ) {
$newstr = mb_substr($str, 0, $length, 'utf-8')
} elseif ( function_exists('iconv_substr') ) {
$newstr = iconv_substr ($str, 0, $length, 'utf-8');
} else {
//$newstr = trim_right(substr($str, 0, $length)); substr($str, 0, $length);
}
if ($append && $str != $newstr) {
$newsstr .= $append;
return $ newstr;
}


ecshop 版の特徴と欠点は、元の文字列に中国語が含まれていない場合 (例: abcd1234)、中国語の文字が 1 文字としてカウントされることです。 4 つの中国語文字または 8 つの英語文字をインターセプトすることを目的としている場合、ecshop バージョンを使用すると、期待される結果が得られません: abcd。以下は簡単なテスト結果です:



コードをコピー

コードは次のとおりです: $str1 = "太陽は山を越え、黄河は海へ";

echo $str1."n";

echo my_sub_str($str1, 4, "...")."n"; //出力: 山には太陽が輝いています...
$str2 = "白1日2伊3山4";
echo $str2."n"; , "...")."n"; // 出力: White 1st 2...



最適化バージョン

中国語の文字列をインターセプトするほとんどのアプリケーション シナリオは次のとおりです。 「元の文字列は中国語、英語、数字の混合にすることができます。中国語の文字は 2 文字としてカウントされ、英語の数字は 1 文字としてカウントされます。」 この要件の実装バージョンは以下に示されています:

コードをコピー

コードは次のとおりです: /*** 文字列インターセプト、中国語の文字は 2 文字として計算され、GBK と UTF-8 エンコーディングの両方がサポートされています

* @param $string インターセプトされる文字列

* @param $length 文字数インターセプトされる
* @param $append 部分文字列に追加された末尾
* @return インターセプトされた文字列を返します
*/
function substring($string, $length, $append = false) {
if ( $length return '';
}
// 元の文字列が UTF-8 でエンコードされているかどうかを確認します
$is_utf8 = false;
$str1 = @iconv("UTF-8", "GBK", $string);
$str2 = @iconv("GBK", "UTF-8", $str1); ( $string == $str2 ) {
$is_utf8 = true;
// UTF-8 エンコードの場合は、GBK エンコードを使用します
$string = $str1>}
$ newstr = '';
for ($i = 0 ; $i $newstr .= ord ($string[$i]) > 127 ? i] . $string[ $i] : $string[$ i];
}
if ( $is_utf8 ) {
$newstr = @iconv("GBK", "UTF-8", $ newstr);
}
if ($append && $newstr != $string) {
$newstr .= $append;
}
return $newstr; >

テスト結果を以下に示します (GBK と UTF-8 の結果は一致しています):



コードをコピー

コードは次のとおりです



$str1 = "太陽は山を越え、黄河は海に流れ込みます。"

echo substring($str1, 4, "..."); n"; // 出力: 昼間... echo substring($str1, 5, ".. .")."n"; // 出力: Bai Riyi... $str2 = "12白 34 位 56 易 78 山"; echo substring($str2, 4, "... ")."n"; // 出力: 12 白... echo substring($str2, 5, "...")."n"; // 出力: 12 白 3...


著者: edwardlost のブログ

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のおすすめ
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート