字符串处理

5.1 字符串声明方式

Lua 支持三种声明字符串的方式:

单引号与双引号

两种方式完全等价,可以互相嵌套:

1
2
3
4
s1 = "双引号字符串"
s2 = '单引号字符串'
s3 = "她说:'你好'"
s4 = '他说:"世界"'

长括号 [[ ]]

长括号用于声明多行字符串,无需转义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
local html = [[
<html>
<body>
<p>Hello Lua</p>
</body>
</html>
]]

-- 如果字符串内有 ]] 需要转义,使用 [=[ ]=]
local code = [=[
local x = 10
local y = 20
print("x + y = " .. x + y)
-- 这里可以安全地使用 ]] 符号
]=]

print(code)

5.2 转义字符

转义 含义
\n 换行
\t 制表符
\\ 反斜杠
\" 双引号
\' 单引号
\r 回车
\b 退格
\a 响铃
\xNN 十六进制字节(例:\x41 为 ‘A’)
\NNN 十进制字节
1
2
3
4
5
6
7
8
9
10
11
12
print("第一行\n第二行")
-- 输出:
-- 第一行
-- 第二行

print("路径:C:\\Users\\Lua")
-- 路径:C:\Users\Lua

print("制表符:\t缩进")
-- 制表符: 缩进

print("\x48\x65\x6C\x6C\x6F") --> Hello(十六进制)

5.3 字符串是不可变值

在 Lua 中,字符串是不可变的。任何修改操作都会创建新的字符串:

1
2
3
4
5
6
7
8
9
local s = "hello"
local t = s:upper()

print(s) --> hello(原字符串不变)
print(t) --> HELLO(新字符串)

-- 修改字符串意味着分配新内存
local a = "abc"
a = a .. "def" -- 创建了 "abcdef","abc" 等待 GC

5.4 字符串库常用函数

Lua 的字符串库函数可以通过 string.func() 或面向对象风格 s:func() 调用。

获取长度

1
2
3
4
5
-- 方式一:长度运算符 #
print(#"hello") --> 5

-- 方式二:string.len
print(string.len("hello")) --> 5

大小写转换

1
2
3
4
local s = "Hello Lua"

print(string.lower(s)) --> hello lua
print(string.upper(s)) --> HELLO LUA

截取子串 string.sub

1
2
3
4
5
6
7
8
9
10
local s = "Hello Lua"

-- string.sub(s, start, end)
print(s:sub(1, 5)) --> Hello(索引从 1 开始)
print(s:sub(7, 9)) --> Lua
print(s:sub(-3)) --> Lua(负数从末尾数)
print(s:sub(7)) --> Lua(从 7 到末尾)
print(s:sub(1, -4)) --> Hello(从开头到倒数第 4)

-- 注意:end 参数是包含的(inclusive)

查找 string.find

1
2
3
4
5
6
7
8
9
10
11
12
13
14
local s = "Hello Lua World"

-- 简单查找(返回起始和结束位置)
local start, stop = s:find("Lua")
print(start, stop) --> 7 9

-- 没找到返回 nil
print(s:find("Python")) --> nil

-- 从指定位置开始查找
print(s:find("o", 5)) --> 8(从第 5 个字符开始找 "o")

-- 使用模式匹配
print(s:find("%u")) --> 1(第一个大写字母位置)

匹配 string.match

1
2
3
4
5
6
7
8
9
local s = "今天是 2026-06-01"

-- 提取匹配的内容
local year = s:match("%d+")
print(year) --> 2026

-- 使用捕获(capture)
local _, month, day = s:match("(%d+)-(%d+)-(%d+)")
print(month, day) --> 06 01

全局匹配 string.gmatch

1
2
3
4
5
6
7
8
9
10
local s = "apple, banana, cherry"

-- 遍历所有匹配
for word in s:gmatch("%a+") do
print(word)
end
-- 输出:
-- apple
-- banana
-- cherry

全局替换 string.gsub

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
local s = "hello world, hello lua"

-- 基本替换
local result, count = s:gsub("hello", "hi")
print(result) --> hi world, hi lua
print(count) --> 2(替换次数)

-- 限制替换次数
result = s:gsub("hello", "hi", 1)
print(result) --> hi world, hello lua

-- 使用函数替换
result = s:gsub("%a+", function(word)
return word:upper()
end)
print(result) --> HELLO WORLD, HELLO LUA

其他实用函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-- 重复字符串
print(string.rep("ab", 3)) --> ababab

-- 反转字符串
print(string.reverse("hello")) --> olleh

-- 格式化字符串
print(string.format("姓名:%s,年龄:%d,分数:%.1f", "张三", 25, 87.5))
--> 姓名:张三,年龄:25,分数:87.5

-- format 格式说明
-- %s 字符串
-- %d 整数
-- %f 浮点数(%.2f 保留两位小数)
-- %x 十六进制
-- %02d 至少两位,不足补零
print(string.format("%02d:%02d:%02d", 8, 5, 3)) --> 08:05:03

5.5 Lua 模式匹配

Lua 的模式匹配不是正则表达式(Regex),而是一个轻量级的替代方案,语法更简洁。

字符类

模式 匹配
. 任意字符
%a 字母
%l 小写字母
%u 大写字母
%d 数字
%w 字母和数字
%s 空白字符
%p 标点符号
%c 控制字符
%x 十六进制数字
%z NULL 字符

大写字母字符类表示补集

  • %D 匹配非数字
  • %U 匹配非大写字母

魔法字符

1
( ) . % + - * ? [ ] ^ $

这些字符有特殊含义,匹配字面量时需要加 % 转义:

1
2
3
4
5
6
7
8
9
-- 匹配点号
print(string.match("hello.world", "%.")) --> .

-- 匹配括号
print(string.match("func(arg)", "%(")) --> (

-- 字符集:匹配方括号内的任意一个字符
print(string.match("hello", "[aeiou]")) --> e(第一个元音)
print(string.match("hello", "[^aeiou]")) --> h(补集,第一个非元音)

数量修饰符

修饰符 含义
+ 一个或多个(最长匹配)
* 零个或多个(最长匹配)
- 零个或多个(最短匹配)
? 零个或一个
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- + 匹配最长的连续序列
print(string.match("123abc456", "%d+")) --> 123

-- * 匹配零个或多个
print(string.match("abc123", "%d*")) --> ""(开头有零个数字)
print(string.match("123abc", "%d*")) --> 123

-- - 最短匹配(和 * 区别在于尽可能短)
local s = "a---b---c"
print(s:match("%a.-%a")) --> a---b(最短)
print(s:match("%a.*%a")) --> a---b---c(最长)

-- ? 匹配零个或一个
print(string.match("color", "colou?r")) --> color
print(string.match("colour", "colou?r")) --> colour

边界与分支

1
2
3
4
5
6
7
8
9
10
-- ^ 匹配开头
print(string.match("hello world", "^hello")) --> hello
print(string.match("say hello", "^hello")) --> nil

-- $ 匹配结尾
print(string.match("hello world", "world$")) --> world
print(string.match("hello world!", "world$")) --> nil

-- 分支 | 需要自己模拟
-- Lua 模式不支持 |,需要用字符集或多次匹配

捕获(Captures)

圆括号 () 用于捕获匹配的子串:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
local s = "2026-06-01"

-- 一次捕获多个
local year, month, day = s:match("(%d+)-(%d+)-(%d+)")
print(year, month, day) --> 2026 06 01

-- 嵌套捕获
local _, inner = string.match("{{content}}", "{(.+)})")
print(inner) --> {content}

-- gsub 中使用捕获引用
local s = "name = John, age = 25"
local result = s:gsub("(%w+) = (%w+)", "%1:%2")
print(result) --> name:John, age:25
-- %1 引用第一个捕获,%2 引用第二个捕获

常用模式示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
-- 验证邮箱(简单版)
local function is_email(s)
return s:match("^[%w%.%%%+%-_]+@[%w%-_]+%.%w+$") ~= nil
end

-- 提取所有数字
local function extract_numbers(s)
local nums = {}
for num in s:gmatch("%d+") do
table.insert(nums, tonumber(num))
end
return nums
end

-- 移除 HTML 标签
local function strip_html(s)
return s:gsub("<[^>]+>", "")
end

-- 模板替换
local function template(tpl, params)
return tpl:gsub("{(%w+)}", params)
end

local tpl = "您好,{name},您的验证码是{code}"
local result = template(tpl, {name = "张三", code = "8848"})
print(result) --> 您好,张三,您的验证码是8848

5.6 本章小结

  • 字符串可用 ""''[[]] 声明
  • .. 连接字符串,字符串不可变
  • 常用函数:subfindmatchgmatchgsubformat
  • 模式匹配是轻量级正则的替代品
  • 字符类 %d%a%w 等,大写为补集
  • 修饰符 +*-? 控制重复次数
  • 捕获 () 提取匹配内容

练习题

  1. 使用 string.gsub 将字符串中的数字替换为 [数字]
  2. "2026-06-01 14:30:00" 中提取年月日时分秒
  3. 实现一个函数检查字符串是否为回文(正反读一样)
  4. 使用模式匹配提取一段文本中所有以 # 开头的标签(如 #Lua#编程
  5. string.format 格式化表格数据:
1
2
3
姓名      年龄      分数
张三 25 87.5
李四 30 92.0
ByteFisher
分享编程技术 · 记录钓鱼乐趣
扫码关注
▸ 扫码关注 ◂
Lua基础教程 系列
第 5/15 篇
分享: