Lua 刪除UTf-8編碼中的特殊字符





首先,我們要對UTF-8有一個基本的認識,根據Wiki上面的解釋:

UTF-8使用一至六個字節爲每個字符編碼(儘管如此,2003年11月UTF-8被RFC 3629重新規範,只能使用原來Unicode定義的區域,U+0000到U+10FFFF,也就是說最多四個字節):
1. 128個US-ASCII字符只需一個字節編碼(Unicode範圍由U+0000至U+007F)。
2. 帶有附加符號的拉丁文、希臘文、西裏爾字母、亞美尼亞語、希伯來文、阿拉伯文、敘利亞文及它拿字母則需要兩個字節編碼(Unicode範圍由U+0080至U+07FF)。
3. 其他基本多文種平面(BMP)中的字符(這包含了大部分常用字,如大部分的漢字)使用三個字節編碼(Unicode範圍由U+0800至U+FFFF)。
4. 其他極少使用的Unicode 輔助平面的字符使用四至六字節編碼(Unicode範圍由U+10000至U+1FFFFF使用四字節,Unicode範圍由U+200000至U+3FFFFFF使用五字節,Unicode範圍由U+4000000至U+7FFFFFFF使用六字節)。

Unicode 和 UTF-8 之間的轉換關係表 ( x 字符表示碼點佔據的位 )
碼點的位數 碼點起值 碼點終值 字節序列 Byte 1 Byte 2 Byte 3 Byte 4 Byte 5 Byte 6
  7 U+0000 U+007F 1 0xxxxxxx
11 U+0080 U+07FF 2 110xxxxx 10xxxxxx
16 U+0800 U+FFFF 3 1110xxxx 10xxxxxx 10xxxxxx
21 U+10000 U+1FFFFF 4 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
26 U+200000 U+3FFFFFF 5 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
31 U+4000000 U+7FFFFFFF 6 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

  • 在ASCII碼的範圍,用一個字節表示,超出ASCII碼的範圍就用字節表示,這就形成了我們上面看到的UTF-8的表示方法,這様的好處是當UNICODE文件中只有ASCII碼時,存儲的文件都爲一個字節,所以就是普通的ASCII文件無異,讀取的時候也是如此,所以能與以前的ASCII文件兼容。
  • 大於ASCII碼的,就會由上面的第一字節的前幾位表示該unicode字符的長度,比如110xxxxx前三位的二進制表示告訴我們這是個2BYTE的UNICODE字符;1110xxxx是個三位的UNICODE字符,依此類推;xxx的位置由字符編碼數的二進制表示的位填入。越靠右的x具有越少的特殊意義。只用最短的那個足夠表達一個字符編碼數的多字節串。注意在多字節串中,第一個字節的開頭"1"的數目就是整個串中字節的數目。


有了基本的認識之後,我們現在假設,只需要一個字節或三個字節的長度的字符。爲了判斷一個字符是多少個字節,我們需要一個函數來判斷UTF-8的第一個字節的連續的1的位有多少個(從最高位開始):

Lua5.3版本

--獲取一個字節中,從最高位開始連續的1的個數
function  get_continuous_1_count_of_byte(num)
    if nil == num then 
        return -1
    end

    local count = 0
    while (num & 0x80 ~= 0) do
        count = count + 1
        num = num << 1
    end
    return count
end


接下來是刪除特殊字符的函數:

-- 刪除字符串中的特殊字符,特殊字符指代 utf-8 編碼中字節數大於或等於4個字節和2個字節的的符號
function delete_special_char(raw_string)
    if nil == raw_string or string.len(raw_string) == 0 then
        return raw_string
    end
    local new_string = {}
    local index_of_raw_string = 1
    while index_of_raw_string <= string.len(raw_string) do
        local count_1_of_byte = get_continuous_1_count_of_byte(string.byte(raw_string, index_of_raw_string))
      
        if count_1_of_byte < 0 then
            return raw_string
        end
      
        if 0 == count_1_of_byte then
            count_1_of_byte = 1
        end
        if count_1_of_byte <= 3 and count_1_of_byte ~= 2 then
            for i = 0, count_1_of_byte - 1 do 
                table.insert(new_string, string.char(string.byte(raw_string, index_of_raw_string + i)))
            end
        end

        index_of_raw_string = index_of_raw_string + count_1_of_byte
    end

    return table.concat(new_string)
end

這樣就只剩下BMP和ASCII碼的字符了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章