1. 概述
本文将介绍在 Kotlin 中如何将字符串(String)按指定规则拆分为多个部分。我们会覆盖常见的分隔符拆分、正则表达式拆分、懒加载拆分以及结果转数组等实用场景。这些技巧在日常开发中非常常见,尤其处理 CSV、日志解析或协议文本时极易踩坑,掌握它们能大幅提升编码效率和健壮性。
2. 按分隔符拆分
Kotlin 提供了简洁而强大的 split()
扩展函数,用于以一个或多个字符作为分隔符进行字符串拆分。
✅ 使用单个分隔符:
val info = "Name,Year,Location"
assertThat(info.split(",")).containsExactly("Name", "Year", "Location")
这会按照逗号 ,
将字符串切分成列表,行为符合预期。
✅ 支持多个分隔符同时使用:
val info = "Name,Year,Location/Time"
assertThat(info.split(",", "/")).containsExactly("Name", "Year", "Location", "Time")
上面的例子中,,
和 /
都被视为有效分隔符,实现多符号混合切割。
✅ 可限制返回元素数量(limit
参数):
val info = "Name,Year,Location/Time/Date"
assertThat(info.split(",", limit = 2)).containsExactly("Name", "Year,Location/Time/Date")
assertThat(info.split(",", "/", limit = 4)).containsExactly("Name", "Year", "Location", "Time/Date")
当设置 limit = 2
时,最多只产生两个元素 —— 第二个元素包含剩余所有未再拆分的内容。这个特性在需要保留部分原始结构时特别有用。
✅ 支持忽略大小写拆分:
val info = "127.0.0.1aaFirefoxAA58"
assertThat(info.split("aa", ignoreCase = true)).containsExactly("127.0.0.1", "Firefox", "58")
通过 ignoreCase = true
实现不区分大小写的匹配,避免因格式不统一导致解析失败。
✅ 使用换行符拆分:lines()
函数
除了自定义分隔符,Kotlin 还提供了专门处理文本行的扩展函数 lines()
:
val info = "First line\nsecond line\rthird"
assertThat(info.lines()).containsExactly("First line", "second line", "third")
该方法自动识别 \n
、\r
和 \r\n
三种常见换行符,适合读取文件或多行输入的场景。
2.1 懒加载拆分(Lazy Split)
⚠️ 注意:所有 split()
的变体返回的都是 List<String>
—— 即 立即执行并生成完整集合。如果源字符串非常大,可能会造成内存浪费。
为此,Kotlin 提供了 splitToSequence()
,它返回一个 Sequence<String>
,支持惰性求值:
val info = "random_text,".repeat(1000)
assertThat(info.splitToSequence(",").first()).isEqualTo("random_text")
在这个例子中,尽管原字符串包含上千个片段,但 splitToSequence()
并不会立刻创建 1000 个元素的列表,而是像迭代器一样按需计算。只有当你调用 .first()
时才会触发第一个元素的拆分。
✅ 优势总结:
- 内存友好,适用于超长字符串或流式处理
- 在链式操作中避免中间集合的创建,提升性能
- 与 Kotlin 的
Sequence
API 完美集成
例如:
info.splitToSequence(",")
.map { it.uppercase() }
.filter { it.startsWith("R") }
.take(5)
.toList()
上述操作在整个序列上是“流水线式”执行的,不会生成多余中间列表。
3. 使用正则表达式拆分
除了字面量分隔符,我们还可以使用正则表达式来定义更复杂的拆分逻辑。
✅ 示例:提取连续数字
val info = "28 + 32 * 2 / 64 = 29"
val regex = "\\D+".toRegex() // 匹配非数字序列
assertThat(info.split(regex)).containsExactly("28", "32", "2", "64", "29")
这里用 \\D+
表示任意长度的非数字字符作为分隔符,从而提取出所有独立的数值。
✅ 也可以直接传入 Java 的 Pattern
对象:
val pattern = Pattern.compile("\\D+")
assertThat(info.split(pattern)).containsExactly("28", "32", "2", "64", "29")
✅ 同样支持 limit
参数:
assertThat(info.split(regex, 3)).containsExactly("28", "32", "2 / 64 = 29")
assertThat(info.split(pattern, 3)).containsExactly("28", "32", "2 / 64 = 29")
⚠️ 常见踩坑点:从 Java 转向 Kotlin 的误区
很多熟悉 Java 的开发者容易犯一个错误:把正则表达式字符串直接传给 split()
。
比如我们要按连续空白字符拆分:
val info = "a b c d"
❌ 错误写法(Java 风格照搬):
assertThat(info.split("\\s+")).containsExactly(info) // ❌ 实际没拆开!
原因:这种方式会被当作字面量字符串 "\\s+"
来匹配,而原字符串中并不存在这样的子串,因此整个字符串被原样保留。
✅ 正确做法:必须显式构造 Regex
对象:
assertThat(info.split(Regex("\\s+"))).containsExactly("a", "b", "c", "d")
// 或更简洁:
assertThat(info.split("\\s+".toRegex())).containsExactly("a", "b", "c", "d")
📌 记住口诀:Kotlin 中用正则拆分,一定要转成 Regex
类型,不能直接传字符串。
4. 拆分结果转数组
默认情况下,split()
返回的是 ArrayList<String>
:
val fruits = "apple,banana,grapes,orange"
val fruitsArrayList = fruits.split(",")
assertEquals("ArrayList", fruitsArrayList::class.simpleName)
但某些场景下我们需要的是 Array<String>
,比如调用 Java 接口、反射或 vararg 参数传递。
✅ 解决方案一:使用 toTypedArray()
val fruitsArray = fruitsArrayList.toTypedArray()
assertEquals("Array", fruitsArray::class.simpleName)
assertEquals(4, fruitsArray.size)
assertEquals("apple", fruitsArray[0])
assertEquals("banana", fruitsArray[1])
assertEquals("grapes", fruitsArray[2])
assertEquals("orange", fruitsArray[3])
这是最常用也最推荐的方式,代码清晰且性能良好。
✅ 解决方案二:使用 Array()
构造器手动构建
val fruitsArray = Array(fruitsArrayList.size) { i -> fruitsArrayList[i] }
assertEquals(4, fruitsArray.size)
assertEquals("apple", fruitsArray[0])
// ...其余断言同上
虽然可行,但语法略显冗余,除非有特殊索引处理需求,否则建议优先使用 toTypedArray()
。
5. 总结
本文系统梳理了 Kotlin 中字符串拆分的核心方法:
- ✅
split(delimiter)
:基础拆分,支持多分隔符、limit 和 ignoreCase - ✅
lines()
:专为换行设计,兼容多种换行符 - ✅
splitToSequence()
:懒加载拆分,节省内存,适合大数据量场景 - ✅
split(regex)
:支持正则表达式,注意必须传Regex
对象而非字符串 - ✅
toTypedArray()
:轻松将 List 转为 Array,满足 Java 互操作需求
📌 最佳实践建议:
- 日常简单拆分用
split()
- 大文本或链式操作优先考虑
splitToSequence()
- 正则拆分务必使用
.toRegex()
或Regex(...)
- 输出为数组时记得调用
toTypedArray()
所有示例代码均已上传至 GitHub:
👉 https://github.com/baeldung/kotlin-tutorials/tree/master/core-kotlin-modules/core-kotlin-strings