第8章 - 字符串与模式匹配
嗨,朋友!我是长安。
这一章我们来聊聊 Lua 的字符串处理。Lua 的字符串库虽然没有 Java 那么丰富,但有一套独特的模式匹配系统,比正则表达式更轻量,在很多场景下够用了。
📖 字符串基础
-- 字符串定义
local s1 = "Hello" -- 双引号
local s2 = 'World' -- 单引号
local s3 = [[
这是多行字符串
可以直接换行
不需要转义符
]]
-- 转义字符(和 Java 一样)
local s4 = "Hello\nWorld" -- 换行
local s5 = "Tab\there" -- 制表符
local s6 = "引号: \"Hi\"" -- 转义引号
-- 字符串长度
print(#"Hello") -- 5
print(string.len("Hello")) -- 5
🔧 string 库常用函数
大小写转换
local s = "Hello World"
print(string.upper(s)) -- HELLO WORLD
print(string.lower(s)) -- hello world
// Java 等价
"Hello World".toUpperCase(); // HELLO WORLD
"Hello World".toLowerCase(); // hello world
子串截取
local s = "Hello World"
print(string.sub(s, 1, 5)) -- Hello(从位置1到5)
print(string.sub(s, 7)) -- World(从位置7到末尾)
print(string.sub(s, -5)) -- World(倒数5个字符)
// Java 等价(注意 Java 索引从 0 开始)
"Hello World".substring(0, 5); // Hello
"Hello World".substring(6); // World
注意
string.sub 的索引从 1 开始,和 Table 一样。Java 的 substring 从 0 开始。
查找
local s = "Hello World"
-- string.find 返回起始和结束位置
local start, finish = string.find(s, "World")
print(start, finish) -- 7 11
-- 找不到返回 nil
local result = string.find(s, "Lua")
print(result) -- nil
// Java 等价
"Hello World".indexOf("World"); // 6(Java 从 0 开始)
"Hello World".indexOf("Lua"); // -1
替换
local s = "Hello World World"
-- string.gsub(源字符串, 模式, 替换值)
local result, count = string.gsub(s, "World", "Lua")
print(result) -- Hello Lua Lua
print(count) -- 2(替换了2次)
-- 限制替换次数
local result2 = string.gsub(s, "World", "Lua", 1)
print(result2) -- Hello Lua World(只替换1次)
// Java 等价
"Hello World World".replaceAll("World", "Lua"); // Hello Lua Lua
"Hello World World".replaceFirst("World", "Lua"); // Hello Lua World
格式化
-- string.format 类似 Java 的 String.format / C 的 printf
local name = "长安"
local age = 25
local score = 98.5
print(string.format("姓名: %s, 年龄: %d, 分数: %.1f", name, age, score))
-- 姓名: 长安, 年龄: 25, 分数: 98.5
| 格式符 | 说明 | 示例 |
|---|---|---|
%s | 字符串 | "hello" |
%d | 整数 | 42 |
%f | 浮点数 | 3.14 |
%.2f | 保留2位小数 | 3.14 |
%x | 十六进制 | ff |
%02d | 补零到2位 | 05 |
%% | 输出 % 本身 | % |
重复和反转
-- 重复
print(string.rep("Ha", 3)) -- HaHaHa
print(string.rep("-", 20)) -- --------------------
-- 反转
print(string.reverse("Hello")) -- olleH
-- 字节码
print(string.byte("A")) -- 65
print(string.char(65)) -- A
🎯 模式匹配
Lua 的模式匹配比正则表达式更轻量。不支持完整的正则,但对于大多数场景够用了。
模式字符
| 字符 | 说明 | 正则等价 |
|---|---|---|
. | 任意字符 | . |
%a | 字母 | [a-zA-Z] |
%d | 数字 | [0-9] |
%l | 小写字母 | [a-z] |
%u | 大写字母 | [A-Z] |
%w | 字母和数字 | [a-zA-Z0-9] |
%s | 空白字符 | \s |
%p | 标点符号 | [[:punct:]] |
%A | 非字母 | [^a-zA-Z] |
%D | 非数字 | [^0-9] |
量词
| 量词 | 说明 | 正则等价 |
|---|---|---|
* | 0 个或多个(贪婪) | * |
+ | 1 个或多个(贪婪) | + |
- | 0 个或多个(非贪婪) | *? |
? | 0 个或 1 个 | ? |
模式匹配示例
local s = "Today is 2024-01-15, temperature is 25.5°C"
-- 查找日期
local year, month, day = string.match(s, "(%d+)-(%d+)-(%d+)")
print(year, month, day) -- 2024 01 15
-- 查找所有数字
for num in string.gmatch(s, "%d+%.?%d*") do
print(num)
end
-- 2024
-- 01
-- 15
-- 25.5
-- 提取邮箱(简单版)
local email = "联系我: zhangsan@example.com 谢谢"
local addr = string.match(email, "%w+@%w+%.%w+")
print(addr) -- zhangsan@example.com
// Java 正则等价
Pattern pattern = Pattern.compile("(\\d+)-(\\d+)-(\\d+)");
Matcher matcher = pattern.matcher(s);
if (matcher.find()) {
System.out.println(matcher.group(1)); // 2024
System.out.println(matcher.group(2)); // 01
System.out.println(matcher.group(3)); // 15
}
string.gmatch — 全局匹配迭代
-- 遍历所有单词
local s = "Hello World Lua Java"
for word in string.gmatch(s, "%a+") do
print(word)
end
-- Hello
-- World
-- Lua
-- Java
-- 解析键值对
local params = "name=长安&age=25&job=developer"
for key, value in string.gmatch(params, "(%w+)=([^&]+)") do
print(key .. " -> " .. value)
end
-- name -> 长安
-- age -> 25
-- job -> developer
📊 字符串方法速查表
| Lua | Java | 说明 |
|---|---|---|
string.len(s) 或 #s | s.length() | 长度 |
string.sub(s, i, j) | s.substring(i-1, j) | 截取 |
string.find(s, pattern) | s.indexOf(str) | 查找 |
string.gsub(s, p, r) | s.replaceAll(p, r) | 替换 |
string.match(s, p) | Pattern/Matcher | 模式匹配 |
string.gmatch(s, p) | Pattern/Matcher | 全局匹配 |
string.format(fmt, ...) | String.format(fmt, ...) | 格式化 |
string.upper(s) | s.toUpperCase() | 转大写 |
string.lower(s) | s.toLowerCase() | 转小写 |
string.rep(s, n) | s.repeat(n) | 重复 |
string.reverse(s) | new StringBuilder(s).reverse() | 反转 |
💡 面向对象风格调用
Lua 字符串支持用冒号语法调用 string 库的方法:
local s = "Hello World"
-- 以下两种写法等价
print(string.upper(s)) -- HELLO WORLD
print(s:upper()) -- HELLO WORLD
print(string.sub(s, 1, 5)) -- Hello
print(s:sub(1, 5)) -- Hello
print(s:find("World")) -- 7 11
print(s:gsub("World", "Lua")) -- Hello Lua 1
推荐
用冒号风格 s:upper() 更简洁,类似 Java 的 s.toUpperCase()。
📝 小结
- Lua 字符串是不可变的(和 Java 的 String 一样)
string库提供了丰富的字符串操作函数- 模式匹配用
%d、%a、%w等而不是正则的\d、[a-zA-Z] - 推荐使用冒号风格调用:
s:upper()、s:find() string.format和 Java 的String.format非常相似
➡️ 下一步
恭喜你!基础教程全部学完了!🎉 接下来可以进入 实战进阶 部分,学习模块化、文件操作、面向对象,以及最重要的——如何在 SpringBoot 项目中使用 Lua!
💪 练习题
- 把字符串
"hello world"转成"Hello World"(首字母大写)。 - 从字符串
"2024-01-15 14:30:00"中提取年、月、日、时、分、秒。 - 写一个函数,统计字符串中数字的个数。
- 用
string.gsub把字符串中所有空格替换成下划线。
答案提示
s:sub(1,1):upper() .. s:sub(2)或使用 gsub + 模式匹配string.match(s, "(%d+)-(%d+)-(%d+) (%d+):(%d+):(%d+)")local _, count = s:gsub("%d", "")利用 gsub 第二个返回值s:gsub("%s", "_")
