Lua: Language: Strings

 9th March 2022 at 10:55am

Lua 的 string 是 不可变的。它是字节序列(byte sequence),因此是编码无关的。

-- length
a = "hello"
#a      --> 5
#"中文" --> 6 (UTF 8 terminal 下)

-- concat
a .. " world"         --> "hello world"
a .. " world " .. 3   --> "hello world 3" (非 string 类型会被转为 string 再拼接)

-- escape sequences
> "hello\nworld"
hello
world

> '"string inside"'
"string inside"

> '\'abc\''
'abc'

-- \ddd 形式,ddd 是一个字节的 10 进制表示,范围 0~255
> "\97"
a
> "\097"  
a

-- \xXX 形式
> "\x61"
a

-- \u{h ... h} 可以指定 unicode codepoint,Lua 会将其转换为 UTF-8 的字节序列
> "\u{4E2D}\u{6587}"
中文

-- 多行字符串 [[]] 
-- 1. 第一个字符如果是换行,会被 Lua 忽略
-- 2. 在其中无法使用上述各种 escape,如 \xXX,\n 等
page = [[
<html>
<head>
  <title>An HTML Page</title>
</head>
<body>
  <a href="http://www.lua.org">Lua</a>
</body>
</html>
]]

-- 如果多行字符串中有非文本的字符,可以用这种方式来表达。
-- Lua 提供了 \z 用来连接多行字符串。
-- 我觉得这种形式并不优雅。不如 Python 的 """ """ 或者 JS 的 ``。
data = "\x00\x01\x02\x03\x04\x05\x06\x07\z
        \x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"

-- 字符串比较时,没有类型转换,比较的是字典序。
> "2" < "15"
false

string 标准库

Lua 的 string 是不可变的。因此 string 库中的函数都 不会修改传入的 string 参数

Lua 的 string 标准库操作的是字节序列(按单字节来),因此你传多字节字符串不会有预期的效果:

> string.reverse("hello")
olleh

> string.reverse("中文")
??歸?

常用的操作:

> string.rep("abc", 3)             --> abcabcabc
> string.reverse("A Long Line!")   --> !eniL gnoL A
> string.lower("A Long Line!")     --> a long line!
> string.upper("A Long Line!")     --> A LONG LINE!

string.sub(s, i, j) 返回一串子字符串。注意 Lua 的 index 是 1-based,且 i, j 是 inclusive 的

> s = "[in brackets]"
> string.sub(s, 2, -2)    --> in brackets
> string.sub(s, 1, 1)     --> [
> string.sub(s, -1, -1)   --> ]

-- 取前 size 位的子串
> size = 100
> string.sub(s, 1, size-1)

string.char() string.byte() 将字符与其数字表示(numeric representation)互转:

print(string.char(97))                     --> a
i = 99; print(string.char(i, i+1, i+2))    --> cde
print(string.byte("abc"))                  --> 97 (默认取第一个字符)
print(string.byte("abc", 2))               --> 98  (取第 2 个字符)
print(string.byte("abc", -1))              --> 99  (取最后一个字符)

-- 一种 pattern,生成 s 的数字表示的 list:
string.byte(s, 1, -1)

格式化字符串 string.format() 与 C 的 printf 一致:

> string.format("x = %d y = %d", 10, 20)   --> x = 10 y = 20
> string.format("x = %x", 200)             --> x = c8
> string.format("x = 0x%X", 200)           --> x = 0xC8
> string.format("x = %f", 200)             --> x = 200.000000

> tag, title = "h1", "a title"
> string.format("<%s>%s</%s>", tag, title, tag)   --> <h1>a title</h1>

-- 控制数字的小数位
> string.format("pi = %.4f", math.pi)       --> pi = 3.1416

-- 控制数字的按 0 填充
> d = 5; m = 11; y = 1990
> string.format("%02d/%02d/%04d", d, m, y)  --> 05/11/1990

查找 string.find() 及全局替换(Global SUBstitution) string.gsub()

> string.find("hello world", "wor")   --> 7   9

> start_index, end_index = string.find("hello world", "wor")
> end_index    -->9

> string.find("hello world", "war")   --> nil

> string.gsub("hello world", "l", ".")     --> he..o wor.d    3
> string.gsub("hello world", "ll", "..")   --> he..o world    1
> string.gsub("hello world", "a", ".")     --> hello world    0

utf8 库

utf8 库提供了对 UTF8 字节序列的操作。

> utf8.len("résumé")   --> 6
> utf8.len("中文")     --> 2

-- Unicode codepoint 与 UTF-8 encoded byte sequence 互转
> utf8.char(114, 233, 115, 117, 109, 233)    --> résumé
> utf8.codepoint("résumé", 6, 7)             --> 109    233