• [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, "[204169]", "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, "[%z1-127194-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"));

  • 相关阅读:
    ElementUI 之 Message,自动弹出,信息不显示问题
    eslint 对下一行不要校验报错
    <input type="file"> accept属性筛选文件类型
    纯 css 控制隔行变色
    本地启动服务,两个进程分别监听两个端口,导致两个 URL 不同
    tap 事件会触发两次问题
    时间宝贵-----
    有些人,得到和失去,你都会后悔!
    前调清新,中调醇厚,后调悠长。
    office 格式定义
  • 原文地址:https://www.cnblogs.com/lyh916/p/8098324.html
Copyright © 2020-2023  润新知