国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

php計(jì)算字符串截取的問題
PHP中文網(wǎng)
PHP中文網(wǎng) 2017-04-11 10:30:44
0
8
704

我頁面上有個(gè)字符串過長需要用省略號(hào)代替的功能,現(xiàn)在我用strlen和substr實(shí)現(xiàn),發(fā)現(xiàn)中文和英文截取文字長度不一樣,導(dǎo)致中文截取的過少,英文的截取的和設(shè)置的長度的一樣。有沒有什么好的方法統(tǒng)一中文和英文一樣!表示無語啊!

PHP中文網(wǎng)
PHP中文網(wǎng)

認(rèn)證0級(jí)講師

reply all(8)
Peter_Zhu

php中編碼是UTF-8的話占3個(gè)字節(jié);是GB2312的話占2個(gè)字節(jié)。推薦你把所有字符設(shè)置成同一種編碼字符處理。php除了strlensubstr之外,還有帶mb_開頭的?。】梢灾付ㄗ址幋a格式例如mb_strlen和mb_substr

$len = mb_strlen($string, 'UTF-8');
$newString = $len>60?mb_substr($string, 0, 60, 'UTF-8'):$string;

試試看

PHPzhong

讓多余的字符串顯示為省略號(hào),截取的方式是一種很落后的方式,而且字符串截取對(duì)于中文和英文截取結(jié)果不一樣。HTML5中可以直接通過css來控制:

overflow: hidden;  //溢出部分影藏
white-space: nowrap;  //文本不進(jìn)行換行
text-overflow: ellipsis;   //當(dāng)文本溢出包含元素時(shí)顯示省略號(hào)

這三個(gè)組合使用即可。

黃舟
    /**
     * 字符串截取方法(支持中英文,截取長度包含省略符)
     * @param  string $string   字符串
     * @param  integer $length  截取長度
     * @param  string $dot      省略符
     * @param  string $charset  編碼
     * @return string
     */
    function strCut($string, $length, $dot = '...', $charset = 'UTF-8') {
        $charset = 'UTF-8';
        $strlen = strlen($string);
        if($strlen <= $length) return $string;
        $string = str_replace(
            array(' ','&nbsp;', '&', '"', '\'', '“', '”', '—', '<', '>', '·', '…'), 
            array(' ',' ', '&', '"', "'", '“', '”', '—', '<', '>', '·', '…'),
            $string
        );
        $strcut = '';
        if (strtolower($charset) == 'utf-8') {
            $length = intval($length-strlen($dot)-$length/3);
            $n = $tn = $noc = 0;
            while ($n < strlen($string)) {
                $t = ord($string[$n]);
                if ($t == 9 || $t == 10 || (32 <= $t && $t <= 126)) {
                    $tn = 1; $n++; $noc++;
                } elseif(194 <= $t && $t <= 223) {
                    $tn = 2; $n += 2; $noc += 2;
                } elseif(224 <= $t && $t <= 239) {
                    $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++;
                }
                if ($noc >= $length) {
                    break;
                }
            }
            if ($noc > $length) {
                $n -= $tn;
            }
            $strcut = substr($string, 0, $n);
            $strcut = str_replace(
                array('∵', '&', '"', "'", '“', '”', '—', '<', '>', '·', '…'), 
                array(' ', '&', '"', '\'', '“', '”', '—', '<', '>', '·', '…'),
                $strcut
            );
        } else {
            $dotlen = strlen($dot);
            $maxi = $length - $dotlen - 1;
            $current_str = '';
            $search_arr = array('&',' ', '"', "'", '“', '”', '—', '<', '>', '·', '…','∵');
            $replace_arr = array('&','&nbsp;', '"', '\'', '“', '”', '—', '<', '>', '·', '…',' ');
            $search_flip = array_flip($search_arr);
            for ($i = 0; $i < $maxi; $i++) {
                $current_str = ord($string[$i]) > 127 ? $string[$i].$string[++$i] : $string[$i];
                if (in_array($current_str, $search_arr)) {
                    $key = $search_flip[$current_str];
                    $current_str = str_replace($search_arr[$key], $replace_arr[$key], $current_str);
                }
                $strcut .= $current_str;
            }
        }
        return $strcut.$dot;
    }

推薦使用這個(gè)方法來避免一下尷尬:

(1) substr截取中文會(huì)出現(xiàn)亂碼的情況:

$string = '中文字符中文字符';
var_dump(substr($string, 0, 10));

結(jié)果:string(10) "中文字?"
原因:中文占3個(gè)字符,substr可能會(huì)把某個(gè)中文截取了一部分,使中文亂碼。

(2) mb_substr截取會(huì)出現(xiàn)字符太長的情況:

$string = '中文字符englishword';
var_dump(mb_substr($string, 0, 10));

結(jié)果:string(18) "中文字符englis"
原因:中文占3個(gè)字符,輸出結(jié)果的字符串實(shí)際占18個(gè)字符,并不是期望的10個(gè)字符。

使用情景:微信支付商品名稱有128個(gè)字符限制,在UTF-8編碼下,中英文字符的總字符長度要控制在128個(gè)以內(nèi),個(gè)人覺得用這個(gè)方法比較合適。

PHPzhong

其它答案錯(cuò)誤的理解

其實(shí)題主的問題是:中文英文截取的長度一樣,這里的長度并非指字符長度(Length、Byte),而是像素寬度(Width)

此理論與UTF-8中漢字是3個(gè)字符無關(guān),其實(shí)某些生僻的漢字、Emoji占有4個(gè)字符。

UTF-8最長是6個(gè)字符長(1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx)。


按照漢字(東亞字系)的字體設(shè)計(jì),一般情況下 1個(gè)漢字 ≈ 2個(gè)英文(數(shù)字、符號(hào)等) 的 像素寬度
如:

1a  12ab  123abc   1234abcd
漢  漢字   漢字漢   漢字漢字

可以看到1個(gè)漢字 ≈ 2個(gè)英文的width

在早期的網(wǎng)站中,一般使用SimSun(宋體),在SimSun的設(shè)計(jì)中,英文的寬度 == 1/2的漢字。
隨著互聯(lián)網(wǎng)的發(fā)展,一般的字體已經(jīng)不能滿足大家的需要,所以字體百花齊放的今天,只能 ≈ (約等于)
比如segmentfault的字符方案中,英文多出了1個(gè)寬度,但是不影響整體效果

要保證截取后的字符等長

實(shí)現(xiàn)

前端:(這是最好的方案)

overflow: hidden;  //此句必須
white-space: nowrap;  //對(duì)于無需換行的場(chǎng)景,可以設(shè)置width/height為固定值
text-overflow: ellipsis;   //此行必須,但是Firefox部分版本不兼容

后端: mb_substr,cutStr(能署名代碼來自于Discuz!可以嗎?)的答案,都是錯(cuò)誤的,這些得到的結(jié)果漢字寬度大于英文的寬度

請(qǐng)查看以下代碼:以UTF-8為例子

/**
 * 移除字符串的BOM
 *
 * @param  string $str 輸入字符串
 * @return string 輸出字符串
 */
function removeBOM($str)
{
    $str_3 = substr($str, 0, 3);
    if ($str_3 == pack('CCC',0xef,0xbb,0xbf)) //utf-8
        return substr($str, 3);
    return $str;
}

/**
 * 按UTF-8分隔為數(shù)組,效率比MB_Substr高
 * 0xxxxxxx
 * 110xxxxx 10xxxxxx
 * 1110xxxx 10xxxxxx 10xxxxxx
 * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
 * 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
 * 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
 *
 * @param string $str 輸入utf-8字符串
 * @return array 返回成一段數(shù)組
 */
function str_split_utf8($str)
{
    return preg_match_all('/./u', removeBOM($str), $out) ? $out[0] : FALSE;
}

/**
 * 按非ascii字符占有幾個(gè)字寬的方式切分字符串,并且不會(huì)將漢字切成半個(gè)
 * 所謂字寬是指,使用默認(rèn)字體顯示時(shí),非ascii字符相比英文字符所占大小,比如:宋體、微軟雅黑中,漢字占兩個(gè)寬度
 * @example $ansi_width = 2 表示漢字等非英文字符按照兩個(gè)字寬長度
 * @example $ansi_width = 1 表示所有字符按一個(gè)字寬長度
 *
 * @param string $string 原始字符
 * @param integer $offset 開始偏移,使用方法和substr一樣,可以為負(fù)數(shù)
 * @param integer $length 長度,使用方法和substr一樣,可以為負(fù)數(shù)
 * @param integer $ansi_width 漢字等非英文字符按照幾個(gè)字符來處理
 * @return string 返回裁減的字符串
 */
function substr_ansi($string, $offset, $length = 0, $ansi_width = 1)
{
    if (empty($string)) return $string;;
    $data = str_split_utf8($string);
    if (empty($data)) return $string;
 
    $as = $_as = array();
    $_start = $_end = 0;
 
    foreach($data as $k => $v)
        $as[$k] = strlen($v) > 1 ? $ansi_width : 1;
 
    $_as_rev = array_reverse($as,true);
    $_as = $offset < 0 ? $_as_rev : $as; 
    $n = 0; $_offset = abs($offset);
    foreach($_as as $k => $v) {
        if ($n >= $_offset) {
            $_start = $k;
            break;
        }
        $n += $v;
    }
    //echo $_start,',';
    $_as = $length <= 0 ? $_as_rev : $as;
    end($_as); list($_end) = each($_as); reset($_as);//給$_end 設(shè)定默認(rèn)值,一直到結(jié)尾
    $n = 0; $_length = abs($length);
    foreach($_as as $k => $v) {
        if ($k >= $_start) {
            if ($n >= $_length) {
                $_end = $k + ($length <= 0 ? 1 : 0);
                break;
            }
            $n += $v;
        }
    }
    //echo $_end,'|||||';
    if ($_end <= $_start)
        return '';
 
    $_data = array_slice($data, $_start, $_end - $_start);
 
    return implode('',$_data);
}

/**
 * 按非ascii字符占有幾個(gè)字寬的方式計(jì)算字符串長度
 * @example $ansi_width = 2 表示漢字等非英文字符按照兩個(gè)字寬長度
 * @example $ansi_width = 1 表示所有字符按一個(gè)字節(jié)長度
 *
 * @param string $string 原始字符
 * @param integer $ansi_width 漢字等非英文字符按照幾個(gè)字寬來處理
 * @return string 返回字符串長度
 */
function strlen_ansi($string, $ansi_width = 1)
{
    if (empty($string)) return 0;
    $data = str_split_utf8($string);
    if (empty($data)) return 0;
 
    $as = 0;
    foreach($data as $k => $v)
        $as += strlen($v) > 1 ? $ansi_width : 1;
    unset($data);
    return $as;
}

/**
 * smarty truncate 代碼算法來自于Smarty
 * @param string
 * @param integer
 * @param string
 * @param boolean
 * @param boolean
 * @return string
 */
function truncate($string, $length = 80, $etc = '...', $break_words = false, $middle = false)
{
    if ($length == 0)
        return '';
    $ansi_as = 2;
    if (strlen_ansi($string, $ansi_as) > $length) {
        $length -= min($length, strlen_ansi($etc, $ansi_as));
        if (!$break_words && !$middle) {
            $string = preg_replace('/\s+?(\S+)?$/u', '', substr_ansi($string, 0, $length+1, $ansi_as));
        }
        if(!$middle) {
           return substr_ansi($string, 0, $length, $ansi_as) . $etc;
        } else {
            return substr_ansi($string, 0, $length/2, $ansi_as) . $etc . substr_ansi($string, -$length/2, 0,  $ansi_as);
        }
    } else {
        return $string;
    }
}

substr_ansi、 truncate便是你要的截取的函數(shù)

// substr_ansi ($offset, $length, $ansi_width)
// 如果ansi_width = 2,則表示將漢字當(dāng)做2個(gè)寬度處理
// offset length 在實(shí)際截取過程中,以英文的長度為準(zhǔn)即可

echo substr_ansi('漢字我愛你', 0, 5, 2);     //輸出:漢字我
echo substr_ansi('漢字abc我愛你', 0, 5, 2);  //輸出:漢字a
echo substr_ansi('abcdef', 0, 5, 2);        //輸出:abcde

echo mb_substr('漢字我愛你', 0, 5);          //輸出:漢字我愛你
echo mb_substr('漢字abc我愛你', 0, 5);       //輸出:漢字abc
echo mb_substr('abcdef', 0, 5);             //輸出:abcde

可以看到上面substr_ansi的截取后的像素寬度是正確的,并且,漢字不會(huì)截取半個(gè)
下面的mb_substr長度明顯不一致

針對(duì)日文、GBK、GB2312、Unicode等情況,請(qǐng)參見:
http://www.load-page.com:8989...
由于實(shí)在沒有精力,以及答主不太懂日文(韓文),有些字符集的ASCII區(qū)域無法弄清楚,但是此代碼在中文方面經(jīng)過生產(chǎn)環(huán)境的驗(yàn)證,已經(jīng)沒有什么問題。有了解東亞,歐洲等字符集的同好,歡迎私信聯(lián)系我。

阿神

text-overflow:ellipsis

Ty80
string mb_strimwidth ( string $str , int $start , int $width [, string $trimmarker = "" [, string $encoding = mb_internal_encoding() ]] )

PHP提供的這個(gè)函數(shù)看起來可以滿足你的要求. $trimmarker 是如果長度超了, 后面添加的...這三字符.

Peter_Zhu
    public static function mb_substr(&$str, $length, $encoding = 'utf-8')
    {
        return isset($str) ? mb_substr($str, 0, $length, $encoding) . ($length < mb_strlen($str, $encoding) ? '...' : '') : '';
    }

https://github.com/letwang/le...

Peter_Zhu

baidu就可以了吧,我基本都是這樣解決的。

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template