使用# 来夺取table长度时需要注意
tableTest = {1,2,7,9,10}
print(#tableTest) ---------------> 5 (这种会自动补上key值)
tableTest1 = {1,2,nil,3,5,7}
print(#tableTest) ---------------> 6
tableTest2= {1,nil,2,nil,3,nil}
print(#tableTest) ---------------> 3
可以看到如果其中元素有nil值的话,#方法是完全失效了
local tab = {}
tab["1"] = 1
tab["2"] = 1
tab["3"] = 1
print(#tab) ----------> 0
如果table的第一个元素key为非数字,那么#tb获取到的长度也是0。
所以在确保table中的键值是从1,2开始连续向后,而且没有nil元素的情况下才可以使用
(如果是从0开始,会忽略0)
int luaH_getn (Table *t) {
unsigned int j = t->sizearray;
if (j > 0 && ttisnil(&t->array[j - 1])) {
/* there is a boundary in the array part: (binary) search for it */
unsigned int i = 0;
while (j - i > 1) {
unsigned int m = (i+j)/2;
if (ttisnil(&t->array[m - 1])) j = m;
else i = m;
}
return i;
}
/* else must find a boundary in hash part */
else if (t->node == dummynode) /* hash part is empty? */
return j; /* that is easy... */
else return unbound_search(t, j);
}
这个是lua5.1中求table长度的方法,是二分查找的思路。用二分法找到一个索引i,使得t[i]存在而t[i+1]为nil,就把i作为table的长度返回。二分查找的条件就是序列是有序,要不查的结果也不可信(像在一堆整数里查看是否有某个值,如果使用二分查找的话,前提就要先排序,然后查找,不先排序的话,找的结果不可信)。序也就是前提条件,这里取table的长度的前提条件就是,从键1到n(n为当前表非负整数key中最大值)所有键对应的值都不为nil ,否则二分查找的前提条件不满足,取长度的结果就不可信。
注意:如果表中还有非整数key-value,#取的结果只是整数部分长度。还有如表tt={1,2,3} tt[1000]=8; tt[2]=nil 后面再进行取长度操作也是不可信的。
适用情况:像我之前项目中一些临时表,初化元素时没有指定key(默认从1开始),如tt={100,200,300,{1,2},"hello world"} ,后面添加用table.insert,没有删除和其他添加元素方式,这种情况使用#取长度就没什么问题。
还可以采用下面的封装方法,获取table的元素个数。注意,pairs 记录的是非nil的元素。
function table.length()
local count = 0
for k,v in paris(table1) do
count = count +1
end
return count
end
获取字符串长度
对于字符串来说,#是获取字符串长度
local str = "abc"
local len = #str
print(len) -- 3
str = "你们好"
len = #str
print(len) -- 9
c#中字符串默认的使用utf-16编码,理论上和unicode编码对应,使用两字节存储一个字符,不管什么字符都是用2个字节存储。
lua呢,lua文件一般读取的时候就采用utf-8编码,字符串也采用utf-8来存储的。utf-8是可变的编码格式。下面就来说一下,utf-8是如何存储的。
相信大家知道unicode字符集吧,包含了全世界的字符,然而它只是规定了字符的二进制编码,并没有规定二级制编码是如何存储的。utf-8就是unicode的一个实现方式,就是怎么存储和读取这个unicode二进制编码。
utf-8是一个可变长的编码方式,有的是用1个字节存,有的采用2个,有的3个,最多可采用6个字节,既然是可变的,就要求字节中有个位数用来表示标记的,,有了标记就知道怎么读取字节了。
1个字节表示的编码,最高位是0,像这样0xxxxxxx,后面7位x,用来表示unicode编码,当然7位表示的编码有限,
不是1个字节的编码,而就是n个字节的编码,就需要第一个字节的前n位用1表示,n+1位用0,其余的字节,前两位是10,如2个字节的 110xxxxx 10xxxxxx,3个字节的1110xxxx 10xxxxxx 10xxxxxx等的,除了符号位,剩下的x就用来表示unicode编码了,例如 "严"的unicode是4E25,二进制是100111000100101,需要16位,能表示16位的utf-8,就需要3个字节了。
总之,在lua中,通过string.len获取的字符串的字节长度,采用utf-8存储的。
在网上下载一份,获取lua字符长度的方法
-- 获取字符串的长度(任何单个字符长度都为1)
function getStringLength(inputstr)
if not inputstr or type(inputstr) ~= "string" or #inputstr <= 0 then
return nil
end
local length = 0 -- 字符的个数
local i = 1
while true do
local curByte = string.byte(inputstr, i)--根据首字节的大小确定
local byteCount = 1
if curByte > 239 then --11110xxx
byteCount = 4 -- 4字节字符
elseif curByte > 223 then --1110xxxx
byteCount = 3 -- 3字节字符
elseif curByte > 128 then --110xxxxx
byteCount = 2 -- 双字节字符
else
byteCount = 1 -- 单字节字符
end
-- local char = string.sub(inputstr, i, i + byteCount - 1)
-- print(char) -- 打印单个字符
i = i + byteCount
length = length + 1
if i > #inputstr then
break
end
end
return length
end
参考:
https://iteacher.blog.csdn.net/article/details/89374675?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link
https://zhuanlan.zhihu.com/p/374527152