1. 程式人生 > >lua 獲取UTF-8中文字串長度-string.byte

lua 獲取UTF-8中文字串長度-string.byte

轉載:https://www.jianshu.com/p/be7fa619bb44

一. UTF-8編碼規則
1.1 UTF-8簡單描述
1.2 UTF-8的中文字元編碼如何生成
二、lua 獲取UTF-8字串長度(含中文)
2.1 lua判斷字元是不是中文
2.2 如何取得位元組ASCII碼 - string.byte()
2.3 字元是由幾個位元組組成
2.4 獲取UTF-8字串長度(含示例)


一、UTF-8編碼規則

1.1 UTF-8簡單描述

UTF-8 是 Unicode 的實現方式之一,其對應關係(編碼規則)如下表所示:

Unicode 可以容納100多萬個符號

Unicode符號範圍 UTF-8位元組數 UTF-8編碼方式(二進位制)
0000 0000-0000 007F (0-127) 1 0xxxxxxx
0000 0080-0000 07FF (128-2047) 2 110xxxxx 10xxxxxx
0000 0800-0000 FFFF (2048-65535) 3 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF (65536-1050623) 4 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

UTF-8 最大的一個特點,就是它是一種變長的編碼方式。它可以使用1~4個位元組表示一個符號,根據不同的符號而變化位元組長度。

  1. 對於單位元組的符號,位元組的第一位設為0,後面7位為這個符號的 Unicode 碼。取值0-127,與標準ASCII 碼一一對應。標準ASCII 碼錶見附錄。
  2. 對於n位元組的符號(n > 1),第一個位元組的前n位都設為1,第n + 1位設為0,後面位元組的前兩位一律設為10。剩下的沒有提及的二進位制位,全部為這個符號的 Unicode 碼。

1.2 UTF-8的中文字元編碼如何生成

例如 將,兩個字從Unicode轉換為UTF-8:

  1. 中 : Unicode 是 0x4E2D(0100 1110 0010 1101),根據上表,處於第三行範圍內,UTF-8編碼需要三個位元組,格式為 1110xxxx 10xxxxxx 10xxxxxx
    的Unicode 二進位制填充進這個格式,得到 11100100 10111000 10101101,轉換為十進位制是 228,184,173
    print(string.char(228,184,173)) =>
  2. 龍 : Unicode 是 0x9F99 (1001 1111 1001 1001) ,同樣處於第三行範圍內。
    UTF-8編碼為11101001 10111110 10011001(233,190,153)
    print(string.char(233,190,153)) =>

input.png

out.png

漢字Unicode碼從漢字對應表中查詢

二、lua 獲取UTF-8字串長度(含中文)

到這裡,已經知道UTF-8的字元、中文是怎麼生成的了,又出現了2個疑問:

  1. 在lua中怎麼判斷一個字元是不是中文?
  2. 這個字元是由幾個位元組組成?

2.1 lua判斷字元是不是中文

通常來說,漢字範圍從0x4E00到0x9FA5,轉換為UTF-8編碼為11100100 10111000 10000000(228, 184, 128) 到 11101001 10111110 10100101(233, 190, 165)
因此,中文UTF-8編碼用3個位元組表示,要遵守格式:1110xxxx 10xxxxxx 10xxxxxx
即第一個位元組的取值區間為 [11100000, 11110000) = [0xe0, 0xf0) = [224, 240) 左開右閉
後兩個位元組的取值區間為[10000000, 10111111] = [0x800xbf] = [128, 191] 開區間

2.2 如何取得位元組ASCII碼 - string.byte()

string.byte()

  • 原型:string.byte (s [, i [, j] ])
  • 解釋:函式返回字元s[i], s[i+1], ···, s[j]的內部數字編碼(ASCII碼),其中引數i的預設值是1,而引數j的預設值是i。

2.3 字元是由幾個位元組組成

讀取第一個位元組,在以下區間的代表不同的位元組數:(有疑問看1.1表)

  1. [0, 0xc0) 表示這個字元僅由1個位元組構成
  2. [0xc0, 0xe0) 表示這個字元由2個位元組構成
  3. [0xe0, 0xf0) 表示這個字元由3個位元組構成
  4. [0xf0, 0xff) 表示這個字元由4個位元組構成
local function Bytes4Character(theByte)
    local seperate = {0, 0xc0, 0xe0, 0xf0}
    for i = #seperate, 1, -1 do
        if theByte >= seperate[i] then return i end
    end
    return 1
end

2.4 獲取UTF-8字串長度

function characters(utf8Str, aChineseCharBytes)
    aChineseCharBytes = aChineseCharBytes or 2
    local i = 1
    local characterSum = 0
    while (i <= #utf8Str) do      -- 編碼的關係
        local bytes4Character = Bytes4Character(string.byte(utf8Str, i))
        characterSum = characterSum + (bytes4Character > aChineseCharBytes and aChineseCharBytes or bytes4Character)
        i = i + bytes4Character
    end

    return characterSum
end

示例: UTF-8字串:我們We

  1. 每一箇中文算一個字元 characters("我們We", 1)

    示例1-程式碼執行.png

     

  2. 遊戲中希望把一個漢字當做2個位元組處理characters("我們We", 2)(因為1個漢字的寬度和2個字母相仿)

示例-程式碼執行.png

附錄

標準ascii碼錶.jpg