PHP擷取UTF8字串 utf-8 可以能佔一個字元 二個字元 或者三個字元
阿新 • • 發佈:2019-01-02
PHP擷取UTF8字串
想必很多人從一開始接觸程式設計到現在,都有一個慣性思維:英文字元佔用一個位元組,中文字元佔用兩個位元組。不錯,英文字元是佔用一個位元組,但中文字元佔用兩個位元組是相對於GBK編碼而言(當然,其他一些編碼如GB2312也是),但是在時下國際流行的UTF8編碼中,一箇中文字元佔用3個位元組。不要驚訝,這是一個事實,而且應該成為一個常識。
UTF8編碼可能出現一個字元佔用1個、2個、3個甚至更多位元組的情況,如英文字元abc佔用一個位元組,中文字元佔用三個位元組,那麼什麼字元佔用兩個位元組呢?這個問題我一開始並沒有發現,只是前幾天有人留言,首頁的評論擷取竟然出現了亂碼的情況:
最開始並沒有發現這兩個亂碼出現的問題在哪裡,後來仔細驗證了下,發現是處在·這個字元上(鍵盤左上角,中文輸入法下),它佔用兩個位元組。而emlog的擷取字串函式,除了英文字元外,預設其他的都佔三個位元組了,因此導致亂碼出現。
查閱了相關資料,得出了一個結論:UTF8編碼的字元中,第一個位元組ASCII值大於等於224的,其與之後的2個位元組一起組成一個UTF8字元,第一個位元組ASCII值大於192等於小於224的,其與之後的1個位元組組成一個UTF-8字元,第一個位元組ASCII值小於192的,其本身成為一個UTF8字元。於是在PHP中將·字元的ASCII打印出來,第一個位元組是194,第二個位元組是183,木有第三個位元組了,於是擷取的字元中,若包含·字元,就會出現亂碼了。
問題找到,解決方案也就很簡單了,分別判斷處理下就OK。寫了如下函式用於擷取:
function subString($str, $start, $length) { $i = 0; //完整排除之前的UTF8字元 while($i < $start) { $ord = ord($str{$i}); if($ord < 192) { $i++; } elseif($ord <224) { $i += 2; } else { $i += 3; } } //開始擷取 $result = ''; while($i < $start + $length && $i < strlen($str)) { $ord = ord($str{$i}); if($ord < 192) { $result .= $str{$i}; $i++; } elseif($ord <224) { $result .= $str{$i}.$str{$i+1}; $i += 2; } else { $result .= $str{$i}.$str{$i+1}.$str{$i+2}; $i += 3; } } if($i < strlen($str)) { $result .= '...'; } return $result; }