lua匹配UTF-8中文漢字
阿新 • • 發佈:2019-01-01
lua5.3雖然支援utf-8,但是自帶的string庫不支援漢字的處理,而且lua的正則實現也比較雞肋,很難匹配中文。所以文章討論UTF-8字符集,中文漢字的表示方法,然後說明lua如何匹配UTF-8中文漢字。
因此,UTF-8可以用來表示字元編碼最多的有效位數是31位,即x代表的位。除掉那些標誌位(如每位元組開頭的10),UTF-8表示的與Unicode編碼是對應的。另外,Unicode相容標準的ASCII字符集,只需要一個位元組就可以表示所有ASCII碼,ASCII碼一共規定了128個字元的編碼,所以實際只要7位表示。而對於1位元組表示的UTF-8編碼,位元組開頭是0,所以UTF-8表示的英文數字,跟ASCII字符集表示的是一樣的。
換成UTF-8碼就是 11100100 10111000 10000000,即 228, 184, 128同理,0x9FA5為 11101001 10111110 10100101,即 233, 190, 165可以看出,中文UTF-8編碼用3個位元組表示。
前面分析了中文UTF-8的編碼範圍了,所以lua只要用 string.byte(s, i) 取到字元的byte值(字符集通常記 code point)。比較第一個位元組是228-233,而且接下來兩個位元組都是 128-191,就可以簡單認定為中文了。這裡以一個例子說明,比如我要過濾特殊字元,保留中文、英文和數字。
http://www.cnblogs.com/chenwenbiao/archive/2011/08/11/2134503.html
初識UTF-8
UTF-8是Unicode的一種實現,是一種變長位元組編碼方式。對於某一個字元的UTF-8編碼,如果只有一個位元組則其最高二進位制位為0;如果是多位元組,其第一個位元組從最高位開始,連續的二進位制位值為1的個數決定了其編碼的位數,其餘各位元組均以10開頭。UTF-8最多可用到6個位元組。 如表:因此,UTF-8可以用來表示字元編碼最多的有效位數是31位,即x代表的位。除掉那些標誌位(如每位元組開頭的10),UTF-8表示的與Unicode編碼是對應的。另外,Unicode相容標準的ASCII字符集,只需要一個位元組就可以表示所有ASCII碼,ASCII碼一共規定了128個字元的編碼,所以實際只要7位表示。而對於1位元組表示的UTF-8編碼,位元組開頭是0,所以UTF-8表示的英文數字,跟ASCII字符集表示的是一樣的。
中文UTF-8
通常都說到,漢字範圍從0x4E00到0x9FA5,這是指Unicode編碼。對於UTF-8還要做轉換。其中,0x4E00 用二進位制表示為 100111000000000換成UTF-8碼就是 11100100 10111000 10000000,即 228, 184, 128同理,0x9FA5為 11101001 10111110 10100101,即 233, 190, 165可以看出,中文UTF-8編碼用3個位元組表示。
lua匹配UTF-8漢字
前面分析了中文UTF-8的編碼範圍了,所以lua只要用 string.byte(s, i) 取到字元的byte值(字符集通常記 code point)。比較第一個位元組是228-233,而且接下來兩個位元組都是 128-191,就可以簡單認定為中文了。這裡以一個例子說明,比如我要過濾特殊字元,保留中文、英文和數字。function filter_spec_chars(s) local ss = {} local k = 1 while true do if k > #s then break end local c = string.byte(s,k) if not c then break end if c<192 then if (c>=48 and c<=57) or (c>= 65 and c<=90) or (c>=97 and c<=122) then table.insert(ss, string.char(c)) end k = k + 1 elseif c<224 then k = k + 2 elseif c<240 then if c>=228 and c<=233 then local c1 = string.byte(s,k+1) local c2 = string.byte(s,k+2) if c1 and c2 then local a1,a2,a3,a4 = 128,191,128,191 if c == 228 then a1 = 184 elseif c == 233 then a2,a4 = 190,c1 ~= 190 and 191 or 165 end if c1>=a1 and c1<=a2 and c2>=a3 and c2<=a4 then table.insert(ss, string.char(c,c1,c2)) end end end k = k + 3 elseif c<248 then k = k + 4 elseif c<252 then k = k + 5 elseif c<254 then k = k + 6 end end return table.concat(ss) end
最後語
題外話,前面寫的過濾特殊字元函式,用lua寫效率不高,所以我還寫了c的版本,有興趣猛擊這裡2016/10/14 修復中文匹配bug,感謝sishui的提示2017/3/2 修正臨時變數k不起作用的問題,提升了效率參考:http://blog.csdn.net/mycwq/article/details/51303353http://www.cnblogs.com/chenwenbiao/archive/2011/08/11/2134503.html