首页 > 技术文章 > 与 字符串 相关的操作 -- lua语言实现(带有浓厚的 lua 语法特性)

rollingyouandme 2019-10-23 15:31 原文

 【写在前面】:lua 中 计算字符串的长度 有一个坑点,“#str” 或 “string.len(str)” 得到的长度是按 “UTF8编码规范” 的字节数,一个汉字占 3 byte。使用string.sub()的时候也要注意。

 

一。功能导向

 

1. 统计目标字符串中 换行符 的数目:
 
    local enterCodeNum = 0    --换行符的数目
    for _ in string.gmatch( str ,  "[\n\r]" ) do   
        enterCodeNum = enterCodeNum + 1
    end
    print("换行符数目",enterCodeNum)
 
【知识点】
 
(1)  string.gmatch的使用: 返回一个迭代器函数,每一次调用这个函数,返回一个在字符串 找到的 下一个 符合 pattern 描述的子串。如果参数 pattern 描述的字符串没有找到,迭代函数返回 nil。【属于lua语法】
 
(2) 匹配模式 :[数个字符类] : 与任何[]中包含的字符类配对. 例如[%w_]与任何字母/数字, 或下划线符号(_)配对 。【属于lua语法】
 
(3) Unix 系统中:每行结尾只有 "<换行>",即 "\n";

Windows 系统中:每行结尾是 "<回车><换行>",即 "\r\n";

Mac 系统中:每行结尾是 "<回车>",即 "\r"。

 

2. 去除 目标字符串 首尾 的空白字符:

function string.clean(input)
    input = string.gsub(input, "^[ \t\n\r]+", "")
    return string.gsub(input, "[ \t\n\r]+$", "")
end
 
【知识点】
 
(1)字符串替换  : string.gsub  (  目标字符串,   被替换者,   替身,   替换次数(省略表示全部替换)   )
       例如:      string.gsub("aaaaa" , "a" , "b" , 3)    结果为  "bbbaa" .
 
(2)匹配模式:
 
[ ] : 与任何[]中包含的字符类配对. 例如[%w_]与任何字母/数字, 或下划线符号(_)配对;
最前面加上尖角号 ^ 将锚定从字符串的开头处做匹配, 在模式最后面加上符号   将使匹配过程锚定到字符串的结尾。 如果 ^ 和 $ 出现在其它位置,则均没有特殊含义,只表示自身;
加号 "+"  表示匹配一或更多个该类的字符, 总是匹配尽可能长的串。
 
【翻译】所以代码翻译为:先将字符串左端的所有空格、水平制表符、回车符、换行符 替换成空字符(也就是删去了)。
然后再将字符串尾部的所有空格、水平制表符、回车符、换行符 替换成空字符。
 
【关于匹配模式的拓展】
 
(1). 刚才的例子中,极其容易与下面这个含义混淆:
  [^数个字符类]: 与任何不包含在[]中的字符类配对. 例如[^%s]与任何非空白字符配对。
但这里的尖角号是在中括号里面的,而上例中的尖角号在括号外,只有它在最开头的时候才表示锚定从字符串的开头处做匹配。
 
(2). 一些常用的匹配规则:
  • .(点): 与任何字符配对
  • %a: 与任何字母配对
  • %c: 与任何控制符配对(例如\n)
  • %d: 与任何数字配对
  • %l: 与任何小写字母配对
  • %p: 与任何标点(punctuation)配对
  • %s: 与空白字符配对
  • %u: 与任何大写字母配对
  • %w: 与任何字母/数字配对

当上述的字符类用 大写 时, 表示与 此字符类的任何字符配对. 例如, %S表示与任何非空白字符配对.例如,'%A'非字母的字符。

因为%是转义符,所以在匹配的时候,想表达真正的百分号 “%” 的时候就要用 “%%”。 也就是说: lua 匹配时 “%%” 才等同于 我们所理解的 “%” 。

如果想把   local a = "Hello%%pWorld"   中的 双百分号替换成单百分号 :  a = a:gsub("%%%%","%%")

 

3. 无差别地计算 目标字符串 中的“长度”:

 

 

二. 语法导向

 

1. string.find() 以及 "捕获物" 的应用:

 

【函数功能】:查找 是否包含某个 子字符串,如果没找到就返回 nil ,如果找到了就返回其位置索引(开头和结尾),例如:

(注意,lua中的下标索引都是从 1 开始的) 

print(string.find("abcde","bc"))  ----输出 2    3

 

(1)关于返回值的接收:

local a, b = string.find("abcde", 'bc')     则 a = 2 , b = 3.

如果只想接收第一个或者第二个返回值 :   

local a = string.find("abcde", 'bc')      则  a = 2   (第二个返回值不去接收就好了)

local _, b = tring.find("abcde", 'bc')    则  b = 3   (这里是虚变量的使用)

 

(2) 关于其第三个参数:

第三个参数表示:从哪里开始查找。 如果不写,就是默认从头开始查找。请看例子:

例1 :     print(string.find("abcde", 'bc', 3) )       输出结果是 nil  :从第三个位置开始查找,当然找不到啦。
例2:   print(string.find("abcdebc", 'bc', 3) )     输出结果是 : 6    7   。也就是说,即使是从第三个位置开始查找,一旦找到了,返回的还是它 在整个字符串中的 位置。不要以为也是从第3个开始算哦,人家只是从第3个开始找而已。
它还有第四个参数,但我不会用。
 
(3) 捕获物:(捕获物并不是只在string.find中能用,这里只是借 string.find() 来讨论。)
 
匹配模式中,在内部用 小括号 括起来的部分被称为 捕获物 。当匹配成功时,由 捕获物 匹配到的字符串中的子串被保存起来,并且会把他们作为返回值。
比如:
例1  :  print(string.find( "abcde","([^c]+)" ))            输出结果 :1     2     ab
 
其中,[^c]+ 就是对捕获物的描述,意思是捕获一个 非 “c” 的字符串并且尽可能长。(加号“+”表示尽可能长地去匹配),所以捕获到了 “ab”,捕获物会被作为返回值。
再如:
 例2 :  local a, b, c = string.find( "abcde",  "([^c]+)",  3 )     则 :a = 4, b = 5, c = “de”
本例中从第3个索引位置开始查询 非“c” 的字符串,所以找到了“de”,并作为捕获物返回了。
 
捕获物可以有多个:
如:
例3     pair = " name = Anna "                                  ---- “name”前后、“=”前后、“Anna”前后都有空格;
   print(string.find(pair, "(%a+)%s*=%s*(%a+)"))       ---- 输出 2     12    name    Anna
 
且星号 “*” 表示匹配前面指定的 0 或多个同类字符, 尽可能匹配更长的符合条件的字串,在本例中 %s* 是 空格符。
(  星号 * 跟加号 + 的区别就是:* 可以找不到,是0或多;而 + 至少得有一个,是1 或多 。 )
 
本例中返回了两个捕获物:name 和 Anna。因为匹配格式中有两组 小括号。
【注意】:接收捕获物的时候,是从第三个返回值开始接收的啊。
 
2.待续

 

推荐阅读