在Java和JavaScript中,我們經常會使用字串(String)提供的length成員(member)來抓取這個字串的字數。由於Java和JavaScript並不像Rust或是Golang程式語言這樣會直接抓到字串在經過編碼之後的位元組數量,而是會得到字元的數量,所以我們很直覺地就會在Java或JavaScript用這樣的方式來計算字串的字數。



例如以下的計算字數函數,好像就可以成功正確計算出字數了啊?

實測看看:

字數正確啊?有什麼問題嗎?

先別急著肯定,再多試試,程式如下:

𩸽讀「ㄌㄨㄥˇ」;𡇙讀「ㄉㄨㄛˇ」;😮是驚訝表情。這些東西應該都只能分別算是一個字,但是使用以上的計算字數函數卻都被計算為兩個字了。

這是因為Java和JavaScript是使用UTF-16來編碼字串,一個字可能會被編碼為2個位元組(byte)或是4個位元組。但Java和JavaScript都認為一個字元(character)是16個位元(即2個位元組),而字串"𩸽""𡇙""😮"在經過UTF-16編碼後都是4個位元組,就會被當成是2個字元。Java和JavaScript的字串提供的length成員能夠取得字元數量。

JavaScript並未直接提供「字元」型別;Java則有提供,即char。在Java中,無法直接將UTF-16編碼後為4個位元組的字當作一個char型別的資料來使用,例如以下這行Java敘述就會造成編譯錯誤:

char c = '𩸽';

所以說,在Java和JavaScript中直接將字元數量視同字串的字數是不安全的!

安全地計算字數

筆者想到的方式還是先把字串進行UTF-8的編碼後再去計算字數。如果您有更好的方式也歡迎提供!

有關於UTF-8字元寬度的說明可以參考下面這篇文章(Rust程式語言):

https://magiclen.org/utf8-width/