[Lua]string與中文


參考鏈接:

https://baike.baidu.com/item/%E5%AD%97%E7%AC%A6%E7%BC%96%E7%A0%81/8446880?fr=aladdin#7

http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html

 http://blog.csdn.net/r0ck_y0u/article/details/51883955

 

一.字符編碼

字符編碼的發展史:ASCII->Unicode->UTF-8

1.ASCII:ASCII碼可以表示所有的英語字符(字母、數字、標點符號等)。ASCII碼是7位編碼(0-127),但由於計算機基本處理單位為字節(1字節=8位),所以一個ASCII字符占一個字節。

2.Unicode:因為一個ASCII字符只能表示256個字符,顯然是存在着局限的(如不能用來表示中文)。而且不同的語言有不同的字符,為了讓世界上所有的字符都有一個唯一的編碼值(如果一個編碼值對應多個字符,就會出現歧義),就出現了Unicode碼。Unicode碼可以容納100多萬個符號,每個符號的編碼都不一樣。但是Unicode碼的缺點是效率不高,比如UCS-4(Unicode的標准之一)規定用4個字節存儲一個符號,那么每個英文字母前都必然有三個字節是0,原本只需1個字節現在卻用了4個字節,這對存儲和傳輸來說都很耗資源。

3.UTF-8:為了提高Unicode的編碼效率,於是就出現了UTF-8編碼。UTF-8可以根據不同的符號自動選擇編碼的長短。在UTF-8中,一個英文占1個字節,一個中文占3個字節。

 

二.string庫

相關api:http://cloudwu.github.io/lua53doc/manual.html#pdf-string.sub

在lua中,string庫都是針對單字節字符編碼的。在UTF-8中,因為英語字符都是單字節字符,所以使用string庫處理英語字符是沒有問題的;但是中文字符是多字節字符,如果使用string庫去處理是不行的。

 1 --UTF-8編碼,一個中文占3個字節
 2 local a1 = "你好啊a"
 3 
 4 print(string.byte(a1,1,4))--第1到第4個字節
 5 print(string.len(a1))--字節總數
 6 local startIndex, endIndex = string.find(a1, "你好")
 7 print(startIndex .. " " .. endIndex)--第1到第6個字節
 8 
 9 print("----------------------------------------------------")
10 local test = ""
11 local test2 = "法?"
12 
13 print(string.len(test))
14 print(string.byte(test,1,10))
15 print(string.byte(test2,1,10))
16 
17 --string.gsub的第二個參數為正則表達式,?表示匹配0個至1個
18 --字節230179176中的230179被替換成989898
19 local str = string.gsub(test, test2, function()
20     print("gsub success!")
21     return "bbb"
22 end)
23 print(str)
24 print(string.byte(str,1,10))
25 print(string.byte("b",1,10))

輸出如下:

 

三.中文處理

 先來測試一下中文是怎樣匹配的:

 1 --為了方便輸出中文,這里使用ANSI編碼
 2 --在ANSI編碼中,1個中文占2個字節
 3 local test = "泰ab"
 4 local result
 5 
 6 print(string.byte(test,1,10))--泰:204169 a:97 b:98
 7 print(type(string.byte(test,1,10)))--數字
 8 
 9 --string.gsub 逐字節匹配
10 print("1.")
11 result = string.gsub(test, "[204169]", "c")
12 print(result)--[204169]:2,0,4,1,6,9的集合,因此匹配失敗
13 
14 print("2.")
15 result = string.gsub(test, "[\204169]", "c")
16 print(result)
17 print(string.byte(result,1,10))--第1個字節204匹配成功
18 print(string.byte("",1,10))--c:99 ゛:16997 b:98
19 
20 print("3.")
21 result = string.gsub(test, "[\204\169]", "c")
22 print(result)--匹配成功2次
23 
24 print("4.")
25 result = string.gsub(test, "[\204][\169]", "c")
26 print(result)--匹配成功1次,將原字符串中的中文替換了

輸出如下:

 

UTF8的編碼規則:

1.字符的第一個字節范圍:(0-127)、(194-244)

2.字符的第二個字節及以后范圍(針對多字節編碼,如漢字):(128-191)

3.(192,193和245-255)不會出現在UTF8編碼中 

根據以上規則就可以得出處理中文的方法了:

 1 --獲取字符數
 2 function GetWordCount(str)
 3     local _,count = string.gsub(str, "[^\128-\193]", "")
 4     return count
 5 end
 6 
 7 --將字符串轉為table
 8 function GetWordTable(str)
 9     local temp = {}
10     for uchar in string.gmatch(str, "[%z\1-\127\194-\244][\128-\191]*") do
11         temp[#temp+1] = uchar
12     end
13     return temp
14 end
15 
16 --utf8
17 local test = "泰ab好了."
18 
19 print(GetWordCount(test))
20 local testT = GetWordTable(test) --%z:匹配0 *:表示0個至任意多個
21 for i=1,#testT do
22     print(testT[i])
23 end

 

四.敏感字處理

敏感字的處理主要體現在取名、聊天上,如果字符串中含有敏感字,則需要將其替換成“*”。一開始我使用的string.gsub方法,但是發現敏感字中有不少是帶有特殊符號,從而使整個字符串變成了一個正則表達式了,發生了正則匹配的錯誤,而正確的做法應該是直接跟敏感字進行對比。后來采用的是string.find方法,因為它可以關閉正則匹配。

 1 local sensitiveWordConfig = {"法?"};
 2 
 3 function GetWordCount(str)
 4     local _, count = string.gsub(str, "[^\128-\193]", "")
 5     return count;
 6 end
 7 
 8 --內部接口:將字符串中的敏感字替換成*(替換一個)
 9 function ReplaceSensitiveWord(originStr, sensitiveWord)
10     local resultStr = originStr;
11     --1:從索引1開始搜索 true:關閉模式匹配
12     local startIndex, endIndex = string.find(originStr, sensitiveWord, 1, true);
13     if (startIndex and endIndex) then
14         local strLen = string.len(originStr);
15         local maskWordCount = GetWordCount(sensitiveWord);
16         local maskWord = "";
17         for i=1,maskWordCount do
18             maskWord = maskWord .. "*";
19         end
20         -- print(string.format("startIndex: %d endIndex: %d", startIndex, endIndex));
21         -- print(string.format("strLen: %s maskWord: %s", strLen, maskWord));
22 
23         if (startIndex == 1) then
24             resultStr = maskWord .. string.sub(originStr, endIndex + 1, -1);
25         elseif (endIndex == strLen) then
26             resultStr = string.sub(originStr, 1, startIndex - 1) .. maskWord;
27         else
28             local str = string.sub(originStr, 1,startIndex - 1);
29             local str2 = string.sub(originStr, endIndex + 1, -1);
30             resultStr = str .. maskWord .. str2;
31         end
32     end
33     return resultStr;
34 end
35 
36 --內部接口:將字符串中的敏感字替換成*(替換所有)
37 function ReplaceSensitiveWordAll(originStr, sensitiveWord)
38     local str = originStr;
39     local str2 = ReplaceSensitiveWord(originStr, sensitiveWord);
40     while (str ~= str2) do
41         str = str2;
42         str2 = ReplaceSensitiveWord(str2, sensitiveWord);
43     end
44     return str2;
45 end
46 
47 --內部接口:是否有該敏感字
48 function HasSensitiveWord(originStr, sensitiveWord)
49     local startIndex, endIndex = string.find(originStr, sensitiveWord, 1, true);
50     if (startIndex and endIndex) then
51         -- print("敏感字:" .. sensitiveWord);
52         return true;
53     else
54         return false;
55     end
56 end
57 
58 --外部接口:敏感字替換
59 function ReplaceMaskWord(content)
60     for k,v in pairs(sensitiveWordConfig) do
61         content = ReplaceSensitiveWordAll(content, v);
62     end
63     return content;
64 end
65 
66 --外部接口:是否有敏感字
67 function HasMaskWord(content)
68     for k,v in pairs(sensitiveWordConfig) do
69         if (HasSensitiveWord(content, v)) then
70             return true;
71         end
72     end
73     return false;
74 end
75 
76 print(ReplaceSensitiveWord("法?123法?", "法?"));
77 print(ReplaceSensitiveWordAll("法?123法?", "法?"));
78 print(HasSensitiveWord("12中法?3文", "法?"));
79 print(ReplaceMaskWord("1法?法?2"));
80 print(HasMaskWord("1法?法?2"));


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM