最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

比較discuz和ecshop的截取字符串函數(shù)php版

 更新時(shí)間:2012年09月03日 23:58:22   作者:  
網(wǎng)上看到一篇文章 discuz和ecshop截取字符串的兩個(gè)函數(shù),比較了一下兩個(gè)版本的函數(shù),都各有局限,只能在特定的前提下使用,但是學(xué)習(xí)一下有利于拓寬思路,了解PHP的擴(kuò)展功能
下面先給出兩個(gè)版本函數(shù)的源代碼以及簡(jiǎn)單測(cè)試,最后我會(huì)給出一個(gè)實(shí)用性更強(qiáng)的字符串截取函數(shù)。需要注意的是:這里討論的字符串截取問(wèn)題都是針對(duì)UTF-8編碼的中文字符串。
discuz版本
復(fù)制代碼 代碼如下:

/**
* [discuz] 基于PHP沒(méi)有安裝 mb_substr 等擴(kuò)展截取字符串,如果截取中文字則按2個(gè)字符計(jì)算
* @param $string 要截取的字符串
* @param $length 要截取的字符數(shù)
* @param $dot 替換截掉部分的結(jié)尾字符串
* @return 返回截取后的字符串
*/
function cutstr($string, $length, $dot = '...') {
// 如果字符串小于要截取的長(zhǎng)度則直接返回
// 此處使用strlen獲取字符串長(zhǎng)度有很大的弊病,比如對(duì)字符串“新年快樂(lè)”要截取4個(gè)中文字符,
// 那么必須知道這4個(gè)中文字符的字節(jié)數(shù),否則返回的字符串可能會(huì)是“新年快樂(lè)...”
if (strlen($string) <= $length) {
return $string;
}
// 轉(zhuǎn)換原字符串中htmlspecialchars
$pre = chr(1);
$end = chr(1);
$string = str_replace ( array ('&amp;', '&quot;', '&lt;', '&gt;' ), array ($pre . '&' . $end, $pre . '"' . $end, $pre . '<' . $end, $pre . '>' . $end ), $string );
$strcut = ''; // 初始化返回值
// 如果是utf-8編碼(這個(gè)判斷有點(diǎn)不全,有可能是utf8)
if (strtolower ( CHARSET ) == 'utf-8') {
// 初始連續(xù)循環(huán)指針$n,最后一個(gè)字位數(shù)$tn,截取的字符數(shù)$noc
$n = $tn = $noc = 0;
while ( $n < strlen ( $string ) ) {
$t = ord ( $string [$n] );
if ($t == 9 || $t == 10 || (32 <= $t && $t <= 126)) {
// 如果是英語(yǔ)半角符號(hào)等,$n指針后移1位,$tn最后字是1位
$tn = 1;
$n++;
$noc++;
} elseif (194 <= $t && $t <= 223) {
// 如果是二字節(jié)字符$n指針后移2位,$tn最后字是2位
$tn = 2;
$n += 2;
$noc += 2;
} elseif (224 <= $t && $t <= 239) {
// 如果是三字節(jié)(可以理解為中字詞),$n后移3位,$tn最后字是3位
$tn = 3;
$n += 3;
$noc += 2;
} elseif (240 <= $t && $t <= 247) {
$tn = 4;
$n += 4;
$noc += 2;
} elseif (248 <= $t && $t <= 251) {
$tn = 5;
$n += 5;
$noc += 2;
} elseif ($t == 252 || $t == 253) {
$tn = 6;
$n += 6;
$noc += 2;
} else {
$n++;
}
// 超過(guò)了要取的數(shù)就跳出連續(xù)循環(huán)
if ($noc >= $length) {
break;
}
}
// 這個(gè)地方是把最后一個(gè)字去掉,以備加$dot
if ($noc > $length) {
$n -= $tn;
}
$strcut = substr ( $string, 0, $n );
} else {
// 并非utf-8編碼的全角就后移2位
for ($i = 0; $i < $length; $i ++) {
$strcut .= ord ( $string [$i] ) > 127 ? $string [$i] . $string [++ $i] : $string [$i];
}
}
// 再還原最初的htmlspecialchars
$strcut = str_replace( array ($pre . '&' . $end, $pre . '"' . $end, $pre . '<' . $end, $pre . '>' . $end ), array ('&amp;', '&quot;', '&lt;', '&gt;' ), $strcut );
$pos = strrpos ( $strcut, chr ( 1 ) );
if ($pos !== false) {
$strcut = substr ( $strcut, 0, $pos );
}
return $strcut . $dot; // 最后把截取加上$dot輸出
}

discuz版本的最大缺陷在于使用 strlen 獲取原始字符串的長(zhǎng)度,并用來(lái)和傳入的要截取長(zhǎng)度參數(shù)(字節(jié)數(shù))進(jìn)行比較,由于UTF-8的中文字符的字節(jié)數(shù)是不固定的,所以就會(huì)面臨這樣的窘境:如果要截取4個(gè)中文字符應(yīng)該指定多大的截取長(zhǎng)度呢?8字節(jié)還是12字節(jié)呢?。。。這是無(wú)法預(yù)計(jì)的,也正是因?yàn)檫@個(gè)問(wèn)題discuz的cutstr實(shí)際是有bug的,通過(guò)下面的測(cè)試結(jié)果能看出:
復(fù)制代碼 代碼如下:

$str1 = "欲窮千里目";
echo my_cutstr($str1, 10, "...")."\n"; // 輸出:欲窮千里目... [這是一個(gè)bug,想想是什么原因?qū)е??]
echo my_cutstr($str1, 15, "...")."\n"; // 輸出:欲窮千里目

導(dǎo)致上述bug的原因在與cutstr函數(shù)在截取字符的時(shí)候是將一個(gè)中文字按2個(gè)字符算,那么5個(gè)中文字就是10字符,而原始字符串的長(zhǎng)度是15字節(jié),所以cutstr認(rèn)為“成功地”從15字符的串上截取了10個(gè)字符,然后加上了“尾巴”。要解決這個(gè)bug只要在判斷一下返回的子串是否和原始串相同,如果相同就不加“尾巴”。
ecshop版
復(fù)制代碼 代碼如下:

/**
* [ecshop] 基于PHP的 mb_substr,iconv_substr 這兩個(gè)擴(kuò)展來(lái)截取字符串,中文字符都是按1個(gè)字符長(zhǎng)度計(jì)算;
* 該函數(shù)僅適用于utf-8編碼的中文字符串。
*
* @param $str 原始字符串
* @param $length 截取的字符數(shù)
* @param $append 替換截掉部分的結(jié)尾字符串
* @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 < 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);
}
if ($append && $str != $newstr) {
$newstr .= $append;
}
return $newstr;
}

ecshop版的特點(diǎn)和缺點(diǎn)都在于將中文字符算作一個(gè)字符,如果原始字符串中不含中文,比如:abcd1234,如果本意是要截取4個(gè)中文字符或者8個(gè)英文字符,那么使用ecshop的版本就得不到期望的結(jié)果,返回值的是:abcd。下面是簡(jiǎn)單的測(cè)試結(jié)果:
復(fù)制代碼 代碼如下:

$str1 = "白日依山盡,黃河入海流";
echo $str1."\n";
echo my_sub_str($str1, 4, "...")."\n"; // 輸出:白日依山...
$str2 = "白1日2依3山4";
echo $str2."\n";
echo my_sub_str($str2, 4, "...")."\n"; // 輸出:白1日2...

優(yōu)化版
截取中文字符串的大部分應(yīng)用場(chǎng)景是“原始字符串可以是中文、英文、數(shù)字混雜的,中文字按2個(gè)字符算,英文數(shù)字按1個(gè)字符算”,針對(duì)這個(gè)需求下面給出一個(gè)實(shí)現(xiàn)版本:
復(fù)制代碼 代碼如下:

/**
* 字符串截取,中文字符按2個(gè)字符計(jì)算,同時(shí)支持GBK和UTF-8編碼
* @param $string 要截取的字符串
* @param $length 要截取的字符數(shù)
* @param $append 添加到子串后的尾巴
* @return 返回截取后的字符串
*/
function substring($string, $length, $append = false) {
if ( $length <= 0 ) {
return '';
}
// 檢測(cè)原始字符串是否為UTF-8編碼
$is_utf8 = false;
$str1 = @iconv("UTF-8", "GBK", $string);
$str2 = @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]) > 127 ? $string[$i] . $string[++$i] : $string[$i];
}
if ( $is_utf8 ) {
$newstr = @iconv("GBK", "UTF-8", $newstr);
}
if ($append && $newstr != $string) {
$newstr .= $append;
}
return $newstr;
}

測(cè)試結(jié)果見(jiàn)下(GBK和UTF-8的結(jié)果一致):
復(fù)制代碼 代碼如下:

$str1 = "白日依山盡,黃河入海流";
echo substring($str1, 4, "...")."\n"; // 輸出:白日...
echo substring($str1, 5, "...")."\n"; // 輸出:白日依...
$str2 = "12白34日56依78山";
echo substring($str2, 4, "...")."\n"; // 輸出:12白...
echo substring($str2, 5, "...")."\n"; // 輸出:12白3...

作者:edwardlost' blog

相關(guān)文章

  • PHP中使用glob函數(shù)實(shí)現(xiàn)一句話刪除某個(gè)目錄下的所有文件

    PHP中使用glob函數(shù)實(shí)現(xiàn)一句話刪除某個(gè)目錄下的所有文件

    這篇文章主要介紹了PHP中使用glob函數(shù)實(shí)現(xiàn)一句話刪除某個(gè)目錄下的所有文件,重點(diǎn)在glob函數(shù)的使用上,需要的朋友可以參考下
    2014-07-07
  • echo, print, printf 和 sprintf 區(qū)別

    echo, print, printf 和 sprintf 區(qū)別

    echo, print, printf 和 sprintf 區(qū)別...
    2006-12-12
  • PHP測(cè)試成功的郵件發(fā)送案例

    PHP測(cè)試成功的郵件發(fā)送案例

    這篇文章主要介紹了一個(gè)測(cè)試成功的PHP郵件發(fā)送案例,需要的朋友可以參考下
    2015-10-10
  • PHPMailer安裝方法及簡(jiǎn)單實(shí)例

    PHPMailer安裝方法及簡(jiǎn)單實(shí)例

    PHPMailer是一個(gè)用PHP寫(xiě)的用于郵件發(fā)送的類,有點(diǎn)像Jmail,相信很多新手和我一樣,開(kāi)始很茫然,不知道怎么安裝,查找了一下,發(fā)現(xiàn)這方面的資料真的少之又少,一個(gè)文章被轉(zhuǎn)載千百次,一搜索全是同一個(gè)內(nèi)容,真不知道說(shuō)什么好,其實(shí)打開(kāi)安裝里的readme就一目了然了,閑話少說(shuō),安裝其實(shí)很簡(jiǎn)單。
    2008-11-11
  • PHP概率計(jì)算函數(shù)匯總

    PHP概率計(jì)算函數(shù)匯總

    做項(xiàng)目的有時(shí)會(huì)弄個(gè)活動(dòng)什么的,來(lái)讓用戶參加,既吸引用戶注冊(cè),又提高網(wǎng)站的用戶活躍度。同時(shí)參加的用戶會(huì)獲得一定的獎(jiǎng)品,有100%中獎(jiǎng)的,也有按一定概率中獎(jiǎng)的,大的比如中個(gè)ipad,小的中個(gè)Q幣。那么我們?cè)诔绦蚶锉厝粫?huì)設(shè)計(jì)到算法,即按照一定的概率讓用戶獲得獎(jiǎng)品。
    2015-09-09
  • php無(wú)序樹(shù)實(shí)現(xiàn)方法

    php無(wú)序樹(shù)實(shí)現(xiàn)方法

    這篇文章主要介紹了php無(wú)序樹(shù)實(shí)現(xiàn)方法,實(shí)例分析了php無(wú)序樹(shù)的實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-07-07
  • 如何在PHP中操作臨時(shí)文件

    如何在PHP中操作臨時(shí)文件

    關(guān)于文件相關(guān)的操作,想必大家已經(jīng)非常了解了,在將來(lái)我們刷到手冊(cè)中相關(guān)的文件操作函數(shù)時(shí)也會(huì)進(jìn)行詳細(xì)的講解。今天,我們先來(lái)了解一下在 PHP 中關(guān)于臨時(shí)文件相關(guān)的一些內(nèi)容。
    2021-05-05
  • php使用標(biāo)簽替換的方式生成靜態(tài)頁(yè)面

    php使用標(biāo)簽替換的方式生成靜態(tài)頁(yè)面

    php可以通過(guò)自帶函數(shù)preg_replace可以用數(shù)組批量替換,不過(guò)用正則表達(dá)式替換效率很低,用起來(lái)也不方便。具體參考php手冊(cè)。有需要的小伙伴可以參考下。
    2015-05-05
  • PHP實(shí)現(xiàn)將HTML5中Canvas圖像保存到服務(wù)器的方法

    PHP實(shí)現(xiàn)將HTML5中Canvas圖像保存到服務(wù)器的方法

    這篇文章主要介紹了PHP實(shí)現(xiàn)將HTML5中Canvas圖像保存到服務(wù)器的方法,可實(shí)現(xiàn)將Canvas圖像保存到服務(wù)器的功能,是非常實(shí)用的技巧,需要的朋友可以參考下
    2014-11-11
  • 簡(jiǎn)單實(shí)用的PHP防注入類實(shí)例

    簡(jiǎn)單實(shí)用的PHP防注入類實(shí)例

    這篇文章主要介紹了簡(jiǎn)單實(shí)用的PHP防注入類實(shí)例,以兩個(gè)簡(jiǎn)單的防注入類為例介紹了PHP防注入的原理與技巧,對(duì)網(wǎng)站安全建設(shè)來(lái)說(shuō)非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2014-12-12

最新評(píng)論

清镇市| 和顺县| 信丰县| 长沙县| 卢龙县| 大石桥市| 开江县| 银川市| SHOW| 呼玛县| 新丰县| 莱芜市| 仁化县| 建阳市| 利辛县| 灵丘县| 焉耆| 班戈县| 东方市| 婺源县| 仙居县| 响水县| SHOW| 惠州市| 青岛市| 育儿| 吴堡县| 云梦县| 玉田县| 贡觉县| 东港市| 大新县| 石景山区| 天峻县| 长丰县| 宣汉县| 秦皇岛市| 武鸣县| 白朗县| 香河县| 黄冈市|