php中可使用strlen或者mb_strlen計算字符串的長度,可是這些長度計算的都是在計算機中表示的長度,並非實際在屏幕上顯示的寬度。以下圖(使用的是arial字體):
最理想的實現方式是使用p_w_picpathttftext計算字符串使用特定字體顯示的寬度:
function tf_strlen($str)
{
return ceil(tf_strwidth($str)/tf_strwidth('測'));
}
function tf_strwidth($str)
{
$im=p_w_picpathcreatetruecolor(10,10);
$r=p_w_picpathttftext($im, 12, 0, 5, rand(14, 16),0, 'arial.ttf', $str);
return $r[2]-$r[0];
}
須要在本地計算機的字體文件夾中找到'arial.ttf',而後上傳到php頁面同級的目錄下。這樣調用tf_strlen獲得的就是字符串在屏幕上的顯示寬度了。可是由於p_w_picpathttftext是GD級別的操做,所以效率很是低,編寫下面的程序驗證
$begin=microtime(true);
$im=p_w_picpathcreatetruecolor(1000,1000);
for($i=0;$i<10000;$i++)
{
p_w_picpathttftext($im, 12, 0, 5, rand(14, 16),0, 'arial.ttf', "rupeng.com 如鵬網 在校不迷茫,畢業即輝煌");
}
$t1=microtime(true)-$begin;
echo 'p_w_picpathttftext:'.$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/>';
運行後發現p_w_picpathttftext的運行時間是strlen的4000多倍,太慢了,並且CPU佔用率很是高,所以被否認。
通過觀察發現arial字體下,漢字的寬度是一致的,而一、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);
}
通過大量的測試,發現和p_w_picpathttftext的運行結果很是接近,而速度則比p_w_picpathttftext高不少,CPU佔用率也低不少。 解決思路對於其餘語言,好比C#、Java等都適用。