次に、最初にソース コードと 2 つのバージョンの関数の簡単なテストを示します。最後に、より実用的な文字列インターセプト関数を示します。ここで説明する文字列インターセプトの問題はすべて、UTF-8 でエンコードされた中国語文字列に関するものであることに注意してください。
ディスクバージョン
/**
* [discuz] PHP には文字列をインターセプトするための mb_substr やその他の拡張機能がインストールされていないという事実に基づいて、中国語の文字がインターセプトされた場合、2 文字として計算されます
* @param $string インターセプトされる文字列
* @param $length インターセプトする文字数
* @param $dot 終了文字列の切り詰められた部分を置き換えます
* @return 切り詰められた文字列を返します
*/
function Cutstr($string, $length, $dot = '...') {
// 文字列がインターセプトする長さよりも短い場合は、直接返されます
// strlen を使用して文字列の長さを取得することには、大きな欠点があります。たとえば、文字列の 4 つの中国語文字をインターセプトする必要があります。 "Happy New Year",
// 次に、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; ( $n < strlen ( $string ) ) {
$t = ord ( $string [$n] );
if ($t == 9 || $t == 10 || (32 <= $t && $t <= 126)) {
// 英語の半角記号などがある場合、$n ポインタは 1 桁戻り、$tn の最後の単語は 1 桁になります
$tn = 1; n++;
$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 桁になります
$tn = 3
$noc; += 2;
} elseif (240 <= $t && $t <= 247) {
$n = 4;
$noc += 2; = $t && $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 < $i ++) {
$strcut ( $string [$i] ) > $string [$i] : $string [$i];
}
}
// 元の htmlspecialchars を復元します
$strcut = str_replace( array ($pre . '&' . $end, $pre . '"' . $end, $ pre . '< ' . $end, $pre . $end )、array ('<'、'>' );
$pos = strcut , chr ( 1 ) );
if ($pos !== false) {
$strcut = substr ( $strcut, 0, $pos ); // 最後に、インターセプトを追加します。 discuz バージョンの最大の欠陥は、strlen を使用して元の文字列の長さを取得し、UTF-8 によりインターセプトされる受信長パラメーター (バイト数) と比較することです。漢字のバイト数は固定されていないため、次のジレンマに直面します。4 つの漢字をインターセプトしたい場合、どのくらいのインターセプト長を指定する必要があるか? 8バイトですか、それとも12バイトですか? 。 。 。これは予測不可能であり、まさにこの問題のため、discuz の Cutstr には実際にバグがあることがわかります。
コードをコピーします
コードは次のとおりです:
$ str1 = "貧しいQianlimuになりたい";
echo my_cutstr($str1, 10, "...")."n"; // 出力: Qianlimu... [これはバグです、原因を考えてください。 ]
echo my_cutstr($str1, 15, "...")."n"; // 出力: 遠くから見る
上記のバグの理由は、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 インターセプトされた文字列を返します
*/
function sub_str($str, $length = 0, $append = '...' ) {
$str = トリム($str);
$strlength = strlen($str);
if ($length == 0 || $length >= $strlength) {
return $str; $length < 0) {
$length = $strlength + $length;
if ($length < 0) {
$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));
$newstr = substr($str, 0, $length); $str ! = $newstr) {
$newstr .= $append;
}
ecshop 版の特徴と欠点は、元の文字列の場合、中国語の文字が 1 文字としてカウントされることです。中国語は含まれません。例: abcd1234。本来の目的が 4 つの中国語文字または 8 つの英語文字をインターセプトすることである場合、ecshop バージョンを使用すると期待した結果が得られず、戻り値は次のようになります: abcd。以下は簡単なテスト結果です:
コードをコピーします
コードは次のとおりです:
$str1 = "太陽は山の上にあり、黄河は海に流れ込みます"; str1."n"; echo my_sub_str($ str1, 4, "...")."n"; // 出力: 百里宜山... $str2 = "白 1ri 2yi 3shan 4"; str2."n"; echo my_sub_str($str2, 4, "...")."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 <= 0 ) {
return '';
}
// 元の文字列が UTF-8 でエンコードされているかどうかを検出
$is_utf8 = false; = @iconv("GBK", "UTF-8", $str1);
if ( $string == $str2 ) {
$is_utf8 = true
// UTF-8 エンコードの場合は、GBK エンコードを使用します
$string = $str1;
$ newstr = ''; for ($i = 0; $i <$length; $i ++) {
$newstr .= ord ($string[$i]) > $string[$i] : $string[$i]
if ($is_utf8) {
$newstr("GBK", "UTF- 8", $newstr);
}
if ($append && $newstr != $string) {
$newstr .= $append;
}
return $newstr;
}
テスト結果は次のとおりです( GBK と UTF-8 の結果は一貫しています):
コードをコピーします
コードは次のとおりです:
$str1 = "太陽は山に沈み、黄河は海に流れ込みます。" ;
echo substring($str1, 4, "...")."n"; // 出力: Bairi...
echo substring($str1, 5, "...")."n"; / 出力: Bairiyi...
$str2 = "12白34日56伊78山" ;
echo substring($str2, 4, "...")."n"; // 出力: 12白.. .
echo substring($str2, 5, "...")."n"; // 出力: 12 白 3...
著者: エドワードロストのブログ
http://www.bkjia.com/PHPjc/325891.htmlwww.bkjia.comtruehttp://www.bkjia.com/PHPjc/325891.html技術記事次に、最初にソース コードと 2 つのバージョンの関数の簡単なテストを示します。最後に、より実用的な文字列インターセプト関数を示します。ここで説明する文字列インターセプトについては注意してください...