溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

為什么說(shuō)php不支持unicode編碼

發(fā)布時(shí)間:2021-07-27 10:26:36 來(lái)源:億速云 閱讀:129 作者:chen 欄目:編程語(yǔ)言

本篇內(nèi)容介紹了“為什么說(shuō)php不支持unicode編碼”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

php不支持unicode是指PHP字符串不保存字符的編碼信息,所以原生操作函數(shù),并不知道二進(jìn)制數(shù)據(jù)該如何對(duì)應(yīng)文本,只能假設(shè)一個(gè)字符對(duì)應(yīng)單個(gè)字節(jié);這樣在處理英文等ascii碼時(shí)就夠用,但對(duì)于中文等多字節(jié)字符,就會(huì)出錯(cuò)。

本文操作環(huán)境:windows7系統(tǒng)、PHP7.1版,DELL G3電腦

php不支持unicode是什么意思?為什么說(shuō)PHP不支持Unicode編碼?

經(jīng)??吹接姓f(shuō)法:PHP不支持Unicode,或者說(shuō)PHP在底層不支持Unicode。雖然我知道PHP編碼很蛋疼,各種字符串處理函數(shù)非常不規(guī)范,但也還能顯示中文,一直沒(méi)弄明白這個(gè)不支持Unicode是什么意思?;艘恍r(shí)間來(lái)梳理這方面的信息。

先從一個(gè)例子來(lái)引入:

一個(gè)PHP腳本如下,假設(shè)文件的編碼是UTF-8:

//文件編碼UTF-8
echo strlen("中文"); // 6
echo substr("中文",0,1) // 亂碼
echo substr("中文",0,3) // 中

很奇怪吧,從上面看,似乎把一個(gè)漢字當(dāng)成了3個(gè)字符。這就要從PHP對(duì)于字符串的存儲(chǔ)上說(shuō)起了。

我總結(jié)了一下,如下:

PHP的字符串,是由字節(jié)(byte)組成的數(shù)組構(gòu)成的。也就是說(shuō),類(lèi)似于C語(yǔ)言 char a[3] = "abc" 這樣,一個(gè)字符占據(jù)一個(gè)字節(jié)。

除此之外,并沒(méi)有存儲(chǔ)文本的編碼信息,也就是說(shuō)PHP并不知道這些字符串的二進(jìn)制數(shù)據(jù),應(yīng)該對(duì)應(yīng)怎樣的編碼。

再進(jìn)一步,PHP會(huì)按照腳本文件的編碼,來(lái)決定字符串的編碼。就比如:$string = "中文";,如果腳本文件是UTF-8,就會(huì)把中文的UTF-8的編碼:E4B8ADE69687給保存起來(lái)。

再進(jìn)一步,如前說(shuō)所,PHP并不保存字符串的編碼信息。所以即便中文保存為:E4B8ADE69687,在字符串原生函數(shù)看來(lái),都只是一串二進(jìn)制數(shù)。所以,PHP原生字符串函數(shù)只能操作單字節(jié)字符!就是把一個(gè)字節(jié)當(dāng)做一個(gè)字符來(lái)處理!

如果想明白了上面幾點(diǎn),上面的代碼例子就自然明白了:

//文件編碼UTF-8
echo bin2hex("中文"); // 可以看到,"中文"對(duì)應(yīng)的二進(jìn)制就是:e4b8ade69687
echo strlen("中文"); // 所以按照單字節(jié)來(lái)統(tǒng)計(jì)長(zhǎng)度,就是6 
echo substr("中文",0,1) // 取0到1個(gè)字節(jié),也就是e4,并不對(duì)應(yīng)某個(gè)字符的編碼,所以亂碼
echo substr("中文",0,3) // 取0到3個(gè)字節(jié),剛好把`中`的編碼取出來(lái)

同理,如果把文件編碼換成GBK或者別的,再實(shí)驗(yàn)也會(huì)得到類(lèi)似的結(jié)果,只不過(guò)GBK一個(gè)漢字占2字節(jié)。

那么到現(xiàn)在,基本可以明白了PHP底層不支持unicode到底說(shuō)的是什么了,總結(jié)如下:

PHP字符串不保存字符的編碼信息,所以原生操作函數(shù),并不知道二進(jìn)制數(shù)據(jù)該如何對(duì)應(yīng)文本,只能【假設(shè)】一個(gè)字符對(duì)應(yīng)單個(gè)字節(jié)。這樣在處理英文等ascii碼時(shí)夠用了,但對(duì)于中文等【多字節(jié)字符】,就會(huì)出錯(cuò)了。

而作為反面,我們可以看看所謂底層支持Unicode的語(yǔ)言的情況:

var string = "中文"
console.log(string.length); // 2
string.substr(0,1) // 中

可以看到,在JS中,能正確識(shí)別和處理多字節(jié)字符。也就是在存儲(chǔ)時(shí),把文本的編碼信息也一并存儲(chǔ)。(這里我猜測(cè)是保存的是文本的Unicode值,并不太確定,因?yàn)椴涣私釰S的底層原理)

那么這里就有疑問(wèn)了,PHP中如何才能正確處理多字節(jié)字符呢?答案就是mbstring擴(kuò)展(具體可看:http://php.net/manual/zh/book.mbstring.php)。所謂mbstring,也就是:multi-byte string ,多字節(jié)字符串。

這套擴(kuò)展中,有一系列與原生字符串函數(shù)對(duì)應(yīng)的函數(shù),能用來(lái)正確處理多字節(jié)字符的情況。如:strlen 對(duì)應(yīng) mb_strlen …… 這些對(duì)應(yīng)函數(shù)中,基本和原生函數(shù)一致,只不過(guò)通常多了一個(gè)可選參數(shù):編碼。

舉例如下:

// 腳本類(lèi)型為UTF-8
echo strlen("中文"); // 6
echo mb_strlen("中文","UTF-8"); //2  使用mb_strlen ,并傳入編碼 utf-8, 就會(huì)把二進(jìn)制E4B8ADE69687當(dāng)做utf-8的處理能正確處理
echo mb_strlen("中文"); //2  如果不傳編碼UTF-8,則函數(shù)會(huì)自動(dòng)確定編碼,文檔說(shuō):如果省略,則使用內(nèi)部字符編碼。所以這里也當(dāng)做UTF-8來(lái)處理。
echo mb_strlen("中文","GBK"); //3,如果傳入編碼GBK,則:e4b8ade69687會(huì)被當(dāng)做gbk來(lái)處理,一個(gè)gbk字符占2字節(jié),所以為:3

“為什么說(shuō)php不支持unicode編碼”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI