目录
注:本系列为《Lua程序设计-第4版》 的读书笔记,其中的见解有不完善的地方,可以在评论区指出,原版请看图书
2. 字符串是不可变值。我们不能像在C语言中那样直接改变某个字符串中的某个字符,可以通过创建一个新字符串的方式来达到修改的目的
3. 像Lua语言中的其他对象(表,函数等)一样,Lua语言中的字符串也是自动内存管理的对象之一。这意味着Lua语言会负责字符串的分配和释放,开放人员不须关注。
4. 使用 连接操作符..(两个点)来进行字符串连接。如果操作数中存在数值,那么Lua语言会先把数值转换成字符串:
注:本系列为《Lua程序设计-第4版》 的读书笔记,其中的见解有不完善的地方,可以在评论区指出,原版请看图书
字符串用于表示文本。在Lua语言中,操作100K 或者 1M个字母组成的字符串的程序也很常见。
一. Lua字符串特性:
1. 字符使用8个比特位来存储;
2. 字符串是不可变值。我们不能像在C语言中那样直接改变某个字符串中的某个字符,可以通过创建一个新字符串的方式来达到修改的目的
a = "one string"
b = string.gsub(a, "one", "another")
print(a) --> one string
print(b) --> another string
3. 像Lua语言中的其他对象(表,函数等)一样,Lua语言中的字符串也是自动内存管理的对象之一。这意味着Lua语言会负责字符串的分配和释放,开放人员不须关注。
可以使用长度操作符 (#) 获取字符串的长度
a = "hello"
print(#a) --> 5
4. 使用 连接操作符..(两个点)来进行字符串连接。如果操作数中存在数值,那么Lua语言会先把数值转换成字符串:
> "Hello " .. "World" --> Hello World
> "result is " .. 3 --> result is 3
二. 字符串常量:
我们可以使用一对双引号或单引号来声明字符串常量:
a = "a line"
b = 'another line'
使用双引号和单引号声明字符串是等价的。它们二者唯一的区别在于,使用双引号声明的字符串中出现单引号时,单引号不用转义;使用单引号声明的字符串中出现双引号时,双引号可以不用转义
Lua语言中的字符串支持下列C语言风格的转义字符:
序号 | 方法&用途 |
1 | \a 响铃 |
2 | \b 退格 |
3 | \f 换页 |
4 | \n 换行 |
5 | \r 回车 |
6 | \t 水平制表符 |
7 | \v 垂直制表符 |
8 | \\ 反斜杠 |
9 | \" 双引号 |
10 | \' 单引号 |
三. 长字符串/多行字符串
像长注释/多行注释一样,可以使用一对双方括号来声明长字符串/多行字符串常量。被方括号括起来的内容可以包括很多行,并且内容中的转义序列不会被转义。此外,如果多行字符串中的第一个字符是换行符,那么这个换行符会被忽略。
page = [[
<html>
<head>
<title>An HTML Page</title>
</head>
<body>
<a href="http://www.lua.org">Lua</a>
</body>
</html>
]]
write(page)
有时字符串有可能有类似 a=b[c[i]] 这样的内容(注意其中的]] ,代表了 长字符串的结束),或者 ,字符串中可能有被注释掉的代码。
为了应对这些情况,可以在两个左方括号之间加上任意数量的等号,如 [===[ 。这样,字符串常量只有在遇到了包括相同数量等号的两个右方括号时才会结束(即,对应前例,]===] ),这样就可以在无须修改原字符串的情况下声明任意的字符串常量了。
我们也可以使用--[=[和]=] 来进行长注释。
使用长字符串可能出现的误区:
由于 Lua语言中的字符串常量可以包含任意字节,但是不能滥用这个特性(例如,会导致某些文本编辑器出现异常)。同时,像"\r\n" 一样的EOF序列在被读取的时候可能会被归一化成"\n"。作为替代方案,最好就是把这些可能引起歧义的二进制数据用十进制数值或十六进制的数值转义序列进行表示,例如“\x13\x01\xA1\xBB”。不过,由于这种转义表示形成的字符串往往很长,所以对于长字符串来说仍可能是个问题。针对这种情况,从Lua5.2开始引入了转义序列\z,该转义符会跳过其后的所有空白字符,直到遇到第一个非空白字符。下列中演示了该转义字符的使用方法:
data = "\x00\x01\x02\x03\x04\x05\x06\x07\z\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
第一行最后的\z会跳过其后的EOF和第二行的制表符,因此在最终得到的字符串中,\x08实际上是紧跟\x07的
四. 强制类型转换
1. 自动转换
针对字符串的所有算术操作会尝试将字符串装换为数值。
并且不仅仅在算术操作时进行这种强制类型装换,还会在任何需要数值的情况下进行,例如函数math.sin的参数
print(10 .. 20) --> 1020
注意:使用连接操作符(两个点)进行字符串连接时,必须要使用 空格 将它们分开,否则Lua语言会把第一个点当成小数点
Lua5.3没有实现强制类型转换与整型的集成,而是采用了另一种更简单和快速的实现方式:
算术运算的规则就是只有在两个操作数都是整型值时结果才是整型。
因此,由于字符串不是整型值,所以任何有字符串参与的算术运算都会被当作浮点运算处理:
> "10" + 1 --> 11.0
2.显式类型转换
序号 | 方法&用途 |
1 | tonumber() 显式地将一个字符串转换成数值 当这个字符串的内容不能表示为有效数字时该函数返回nil;否则,该函数就按照Lua语法扫描器的规则返回对应的整型值或浮点类型值: 默认情况下,函数tonumber使用的是十进制,但是也可以指明使用二进制到三十六进制之间的任意进制: |
2 | tostring() 将数值转换成字符串 |
五. 字符串标准库
序号 | 方法&用途 |
1 | 函数string.len(s) 返回字符串s的长度,等价于 #s |
2 | 函数string.rep(s, n) 返回将字符串s重复n次的结果 可以通过调用 string.rep("a", 2^20),创建一个1MB大小的字符串,用于测试 |
3 | 函数string.reverse(s) 用于字符串翻转 |
4 | 函数string.lower(s) 返回一份s的副本,其中所有的大写字母都被转换成小写字母,其他字符则保持不变 |
5 | 函数string.upper() 同上,只是把小写字母转换成大写字母 |
6 | 函数string.sub(s, i, j) 从字符串s中提取第i个到第j个字符(包括第i个 和 第j个字符,字符串的第一个字符索引为1); 该函数支持负数索引。负数索引从字符串的结尾开始技数:索引-1代表字符串的最后一个字符,索引-2代表倒数第二个字符,以此类推。 string.sub(s, 1, j) 得到的是字符串s中长度为j的前缀 string.sub(s, j, -1) 得到的是字符串s中从第j个字符开始的后缀 string.sub(s, 2, -2) 返回的是去掉字符串s第一个和最后一个字符后的结果 注意:Lua语言中的字符串是不可变的。函数string.sub 不会改变原有字符串的值,它只会返回一个新字符串,如果需要改变原字符串,那么必须把新的值赋值过去: |
7 | 函数 string.char() 接收零个或多个整数作为参数,然后将每个整数转换成对应的字符,最后返回由这些字符连接而成的字符串 |
8 | 函数 string.byte(s, i) 返回字符串s中第1个字符的内部数值表示,第二个参数是可选的。有点像string.char()反过来 |
9 | 函数 string.format() 用于进行字符串格式化和将数值输出为字符串的强大工具。 该函数会返回第一个参数(也就是所谓的格式化字符串)的副本,其中的每一个指示符都会替换为使用对应格式进行格式化后的对应参数。类似于 C语言的printf 格式化字符串。 一个指示符由一个百分号和一个代表格式化方式的字母组成, d代表一个十进制整数、 x代表一个十六进制整数、 f代表一个浮点数、 s代表一个字符串,等等。 |
10 | 函数 string.find() 用于在指定的字符串中进行模式搜索: 如果该函数在指定的字符串中找到了匹配的模式,则返回模式的开始和结束位置,否则返回nil |
11 | 函数 string.gsub() 则把所有匹配的模式用另一个字符串替换: 该函数的第二个返回值中返回发生替换的次数 |