前置知识: Lua

标准库详解

2 minIntermediate2026/6/13

Lua标准库详解:字符串库、表库、数学库、IO库、操作系统库与调试库。

1. 字符串库(string)

1.1 基本操作

-- 字符串长度
local s = "Hello, Lua!"
print(string.len(s))    -- 11
print(#s)               -- 11(推荐写法)

-- 字符串拼接
local name = "World"
local greeting = "Hello, " .. name .. "!"

-- 大小写转换
print(string.upper("hello"))   -- "HELLO"
print(string.lower("WORLD"))   -- "world"

-- 子串
print(string.sub("Hello World", 1, 5))   -- "Hello"
print(string.sub("Hello World", 7))      -- "World"
print(string.sub("Hello World", -5))     -- "orld"(负索引从末尾计)

-- 重复
print(string.rep("Ha", 3))  -- "HaHaHa"

-- 反转
print(string.reverse("abc"))  -- "cba"

1.2 查找与匹配

-- find: 查找子串位置
local s = "Hello, Lua World!"
local start, finish = string.find(s, "Lua")
print(start, finish)  -- 8  10

-- 支持模式匹配
local start2 = string.find(s, "%a+")  -- 查找第一个单词
print(start2)  -- 1

-- match: 匹配并返回
local date = "2026-06-13"
local y, m, d = string.match(date, "(%d+)-(%d+)-(%d+)")
print(y, m, d)  -- 2026  06  13

-- gmatch: 全局匹配迭代器
local text = "Hello World, Hello Lua"
for word in string.gmatch(text, "%a+") do
    print(word)  -- Hello, World, Hello, Lua
end

-- gsub: 全局替换
local result = string.gsub("hello world", "l", "L")
print(result)  -- "heLLo worLd"

-- 限制替换次数
local result2 = string.gsub("hello world", "l", "L", 1)
print(result2)  -- "heLlo world"

-- 使用捕获组
local result3 = string.gsub("2026-06-13", "(%d+)-(%d+)-(%d+)", "%3/%2/%1")
print(result3)  -- "13/06/2026"

1.3 模式匹配语法

-- 字符类
-- %a  字母
-- %d  数字
-- %l  小写字母
-- %u  大写字母
-- %w  字母和数字
-- %s  空白字符
-- %p  标点符号
-- %c  控制字符
-- 大写版本表示补集:如%A表示非字母

-- 量词
-- +    1次或多次(贪婪)
-- *    0次或多次(贪婪)
-- -    0次或多次(非贪婪)
-- ?    0次或1次

-- 实用模式
local email = "user@example.com"
local user, domain = string.match(email, "([%w%.%+%-]+)@([%w%.%-]+)")
print(user, domain)  -- user  example.com

local url = "https://example.com:8080/path"
local protocol, host, port, path = string.match(url, "^(%w+)://([%w%.%-]+):?(%d*)(.*)")
print(protocol, host, port, path)

1.4 格式化

-- string.format: 类似C的printf
print(string.format("Hello, %s!", "World"))       -- Hello, World!
print(string.format("Number: %d", 42))             -- Number: 42
print(string.format("Float: %.2f", 3.14159))       -- Float: 3.14
print(string.format("Hex: %x", 255))               -- Hex: ff
print(string.format("Oct: %o", 8))                 -- Oct: 10
print(string.format("Padding: %05d", 42))          -- Padding: 00042
print(string.format("Left: %-10s|", "hi"))         -- Left: hi        |

2. 表库(table)

2.1 插入与删除

local fruits = {"apple", "banana", "cherry"}

-- table.insert: 插入元素
table.insert(fruits, "date")           -- 末尾插入
table.insert(fruits, 2, "blueberry")   -- 在位置2插入
-- {"apple", "blueberry", "banana", "cherry", "date"}

-- table.remove: 删除元素
local removed = table.remove(fruits)    -- 删除并返回末尾元素 "date"
local removed2 = table.remove(fruits, 1) -- 删除并返回位置1 "apple"
-- {"blueberry", "banana", "cherry"}

-- table.sort: 排序
local nums = {3, 1, 4, 1, 5, 9, 2, 6}
table.sort(nums)
-- {1, 1, 2, 3, 4, 5, 6, 9}

-- 自定义排序
local people = {
    {name = "Alice", age = 25},
    {name = "Bob", age = 30},
    {name = "Charlie", age = 20},
}
table.sort(people, function(a, b) return a.age < b.age end)

2.2 其他表操作

-- table.concat: 连接数组元素
local parts = {"Hello", "World", "Lua"}
print(table.concat(parts, ", "))  -- "Hello, World, Lua"

-- table.maxn: 最大正整数索引(Lua 5.1)
-- Lua 5.3+ 使用 # 操作符

-- 表的深拷贝
function deep_copy(orig)
    local copy
    if type(orig) == "table" then
        copy = {}
        for k, v in pairs(orig) do
            copy[deep_copy(k)] = deep_copy(v)
        end
        setmetatable(copy, deep_copy(getmetatable(orig)))
    else
        copy = orig
    end
    return copy
end

-- 表合并
function merge_tables(...)
    local result = {}
    for _, t in ipairs({...}) do
        for k, v in pairs(t) do
            result[k] = v
        end
    end
    return result
end

local merged = merge_tables({a = 1, b = 2}, {b = 3, c = 4})
-- {a = 1, b = 3, c = 4}

3. 数学库(math)

3.1 基本数学函数

-- 常量
print(math.pi)       -- 3.1415926535898
print(math.huge)     -- inf
print(math.maxinteger)  -- 最大整数
print(math.mininteger)  -- 最小整数

-- 取整
print(math.floor(3.7))    -- 3(向下取整)
print(math.ceil(3.2))     -- 4(向上取整)
print(math.abs(-5))       -- 5(绝对值)

-- 最值
print(math.max(1, 5, 3))  -- 5
print(math.min(1, 5, 3))  -- 1

-- 幂与对数
print(math.sqrt(16))       -- 4
print(math.pow(2, 10))     -- 1024
print(math.exp(1))         -- 2.718281828459
print(math.log(100))       -- 4.6051701859881
print(math.log(100, 10))   -- 2(以10为底)

-- 三角函数(弧度制)
print(math.sin(math.pi / 2))  -- 1
print(math.cos(0))             -- 1
print(math.tan(math.pi / 4))  -- 1

-- 角度弧度转换
print(math.rad(180))   -- 3.1415926535898
print(math.deg(math.pi))  -- 180

3.2 随机数

-- 设置随机种子
math.randomseed(os.time())

-- 生成随机数
print(math.random())         -- [0, 1) 随机浮点数
print(math.random(10))       -- [1, 10] 随机整数
print(math.random(5, 10))    -- [5, 10] 随机整数

-- 随机选择
function random_choice(t)
    return t[math.random(#t)]
end

local colors = {"red", "green", "blue"}
print(random_choice(colors))

-- 洗牌算法
function shuffle(t)
    for i = #t, 2, -1 do
        local j = math.random(i)
        t[i], t[j] = t[j], t[i]
    end
    return t
end

4. IO 库

4.1 文件操作

-- 打开文件
local file = io.open("test.txt", "r")  -- r/w/a/r+/w+/a+

if file then
    -- 读取整个文件
    local content = file:read("*a")
    print(content)

    -- 逐行读取
    file:seek("set")  -- 回到文件开头
    for line in file:lines() do
        print(line)
    end

    file:close()
end

-- 写入文件
local outfile = io.open("output.txt", "w")
if outfile then
    outfile:write("Hello, Lua!\n")
    outfile:write("Second line\n")
    outfile:close()
end

-- 追加写入
local appendfile = io.open("output.txt", "a")
if appendfile then
    appendfile:write("Appended line\n")
    appendfile:close()
end

4.2 简化 IO

-- io.read: 从标准输入读取
-- io.write: 写到标准输出

-- 临时文件
local tmp = io.tmpfile()
tmp:write("temporary data")
tmp:seek("set")
print(tmp:read("*a"))  -- "temporary data"
tmp:close()

-- 文件存在检查
function file_exists(path)
    local f = io.open(path, "r")
    if f then
        f:close()
        return true
    end
    return false
end

5. 操作系统库(os)

5.1 时间与日期

-- 当前时间戳
print(os.time())  -- 如 1781365236

-- 格式化日期
print(os.date())           -- "06/13/26 14:30:36"
print(os.date("%Y-%m-%d")) -- "2026-06-13"
print(os.date("%H:%M:%S")) -- "14:30:36"

-- 常用格式符
-- %Y  四位年份    %m  月份(01-12)  %d  日(01-31)
-- %H  小时(00-23) %M  分钟(00-59)  %S  秒(00-59)
-- %A  星期名      %B  月份名        %w  星期(0-6)

-- 从时间戳构造日期
local timestamp = os.time({year = 2026, month = 6, day = 13})
print(os.date("%Y-%m-%d", timestamp))  -- "2026-06-13"

-- 时间差计算
local t1 = os.time()
-- ... 执行一些操作 ...
local t2 = os.time()
print(string.format("耗时: %.2f秒", os.difftime(t2, t1)))

5.2 系统操作

-- 执行系统命令
os.execute("mkdir -p temp")
local result = os.execute("ls -la")
print("命令结果:", result)

-- 获取环境变量
print(os.getenv("HOME"))    -- 用户主目录
print(os.getenv("PATH"))    -- 系统PATH
print(os.getenv("SHELL"))   -- 当前Shell

-- 退出程序
-- os.exit(0)  -- 正常退出
-- os.exit(1)  -- 异常退出

-- 重命名和删除文件
os.rename("old.txt", "new.txt")
os.remove("unwanted.txt")

6. 调试库(debug)

6.1 调试信息

-- 获取调用栈
function foo()
    function bar()
        print(debug.traceback("调用栈:"))
    end
    bar()
end
foo()

-- 获取函数信息
local info = debug.getinfo(1)  -- 当前函数
print("函数名:", info.name)
print("源文件:", info.source)
print("行号:", info.currentline)
print("类型:", info.what)

-- 获取局部变量
function show_locals()
    local x = 10
    local y = "hello"
    local i = 1
    while true do
        local name, value = debug.getlocal(1, i)
        if not name then break end
        print(name, "=", value)
        i = i + 1
    end
end
show_locals()

7. 常见问题与解决方案

7.1 字符串索引从1开始

-- Lua字符串和数组索引从1开始
local s = "Hello"
print(string.sub(s, 1, 1))  -- "H"(不是s[0])
print(s:sub(1, 3))           -- "Hel"(方法调用语法)

7.2 模式匹配不是正则表达式

-- Lua的模式匹配比正则简单,但有差异
-- 用 % 转义而非 \
-- 不支持 | (或)、{n,m} 等语法
-- 非贪婪用 - 而非 *?

-- 匹配IP地址
local ip = "192.168.1.1"
local a, b, c, d = ip:match("(%d+)%.(%d+)%.(%d+)%.(%d+)")
print(a, b, c, d)  -- 192  168  1  1

7.3 table.sort 只对数组部分有效

-- table.sort 只排序连续整数索引部分
local mixed = {3, 1, 2, key = "value"}
table.sort(mixed)  -- 只排序 3, 1, 2

8. 总结与最佳实践

8.1 标准库使用建议

  1. 字符串操作:使用 : 方法调用语法(s:sub() 优于 string.sub(s)
  2. 表操作:注意数组部分和哈希部分是独立的
  3. 随机数:始终设置 math.randomseed
  4. 文件操作:始终检查 io.open 返回值,使用 pcall 处理异常
  5. 模式匹配:Lua模式不是正则,注意 % 转义

8.2 性能建议

  • 字符串拼接使用 table.concat 而非 .. 循环拼接
  • 预编译模式:string.format.. 拼接更高效
  • 大表操作注意 # 操作符只计算数组部分
  • 使用 local 缓存库函数引用local sub = string.sub