我自己寫的js版參考以下文章做出的
http://www.rupeng.com/innersupesite/index.php/7/viewspace-583
JS版:
function arial_strlen(val, word_length){
var lencounter=0;
var sub_str = 0;
for (var i = 0; i < val.length; i++) {
if(ck_null(word_length) != '-'){
if(Math.ceil(lencounter*2) >= word_length){
return sub_str;
}
}
ch = val.substr(i,1);
var char_050 = ",./;'[]=-/*-!@#$%^&*()_{}:\"<>?1234567890fijlrIt";
asc_ch = ch.charCodeAt();
//if(ord(ch)>128){
if (ch.match(/[^\x00-\xff]/ig) != null){
lencounter++;
}else if(char_050.indexOf(ch) != -1){
lencounter+=0.5;
}else if(asc_ch>=48 && ch<=57){
lencounter+=0.55;
}else if(asc_ch>=97 && asc_ch<=122){//a~z
lencounter+=0.55;
}else if(asc_ch>=65 && asc_ch<=90){//A~Z
lencounter+=0.8;
}else{
lencounter++;
}
sub_str++;
}
return Math.ceil(lencounter*2);
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
php中可以使用strlen或者mb_strlen計算字符串的長度,但是這些長度計算的都是在計算機中表示的長度,並不是實際在屏幕上顯示的寬度。
最理想的實現方式是使用imagettftext計算字符串使用特定字體顯示的寬度:
function tf_strlen($str)
{
return ceil(tf_strwidth($str)/tf_strwidth('測'));
}
function tf_strwidth($str)
{
$im=imagecreatetruecolor(10,10);
$r=imagettftext($im, 12, 0, 5, rand(14, 16),0, 'arial.ttf', $str);
return $r[2]-$r[0];
}
需要在本地計算機的字體文件夾中找到'arial.ttf',然後上傳到php頁面同級的目錄下。這樣調用tf_strlen得到的就是字符串在屏幕上的顯示寬度了。但是因為imagettftext是GD級別的操作,因此效率非常低,編寫下面的程序驗證
$begin=microtime(true);
$im=imagecreatetruecolor(1000,1000);
for($i=0;$i<10000;$i++)
{
imagettftext($im, 12, 0, 5, rand(14, 16),0, 'arial.ttf', "rupeng.com 如鵬網在校不迷茫,畢業即輝煌");
}
$t1=microtime(true)-$begin;
echo 'imagettftext:'.$t1.'<br/>';
$begin=microtime(true);
for($i=0;$i<10000;$i++)
{
strlen("rupeng.com 如鵬網在校不迷茫,畢業即輝煌");
}
$t2=microtime(true)-$begin;
echo 'strlen:'.$t2.'<br/>';
echo $t1/$t2.'<br/>';
運行後發現imagettftext的運行時間是strlen的4000多倍,太慢了,而且CPU佔用率非常高,因此被否定。
經過觀察發現arial字體下,漢字的寬度是一致的,而1、i、l等字符的寬度大約是漢字的0.4倍,而阿拉伯數字(除了1)的寬度則是漢字的約0.7倍,小寫字母(除了i、l等)的寬度是漢字的約0.7倍,大寫字母則是漢字的0.8倍,其他字符也可以得出相應的倍率。因此我編寫了下面程序用來計算字符串佔的寬度(單位是1/2的中文寬度)。
function arial_strlen($str)
{
$lencounter=0;
for($i=0;$i<strlen($str);$i++)
{
$ch=$str[$i];
if(ord($ch)>128)
{
$i++;
$lencounter++;
}
else if($ch=='f'||$ch=='i'||$ch=='j'||$ch=='l'||$ch=='r'||$ch =='I'
||$ch=='t'||$ch=='1'
||$ch=='.'||$ch==':'||$ch==';'||$ch=='('||$ch==')'
||$ch=='*'||$ch=='!'||$ch=='\'')
{
$lencounter+=0.4;
}
else if($ch>='0'&&$ch<='9')
{
$lencounter+=0.7;
}
else if($ch>='a'&&$ch<='z')
{
$lencounter+=0.7;
}
else if($ch>='A'&&$ch<='Z')
{
$lencounter+=0.8;
}
else
{
$lencounter++;
}
}
return ceil($lencounter*2);
}
經過大量的測試,發現和imagettftext的運行結果非常接近,而速度則比imagettftext高很多,CPU佔用率也低很多。
解決思路對於其他語言,比如C#、Java等都適用。