Kotlin 使用 String 代表字符串。字符串表示一个有序的字符集合,例如“google.com”、 ”好好学习”等都代表字符串,字符串也可被当成多个字符的有序集合。
1 字符串类型
String 类型是一种快速、现代化的字符串实现,字符串中的每一个字符都由独立的 Unicode 字符组成, String 允许通过形如 s[i] 的格式来访问字符串指定索引处的字符,也可通过 for 循环遍历字符串中的每一个字符。
fun main(args: Array<String>) {
var str = "google.com"
println(str[2]) // 输出 o
println(str[3]) // 输出 g
println(str[6]) // 输出 .
// 遍历 str 字符串中的每一个字符
for (c in str) {
println(c)
}
}
kotlin 的字符串有两种字面值,分别如下:
- 转义字符串:转义字符串可以有转义字符,转义字符串很像 Java 字符串。
- 原始字符串:原始字符串可以包含换行和任意文本,原始字符串需要用3 个引号引起来。
示例如下:
fun main(args: Array<String>) {
// 定义普通字符串
var str = "alibaba.com"
println("长度为:"+str.length)
println("----------------")
// 定义原始字符串
val txt = """
|无聊望见了犹豫
|达到理想不太易
|即使有信心
|斗志却抑制
""".trimMargin()
println(txt)
println("----------------")
// 定义原始字符串
val txt2 = """
^海阔天空
^今天我
^寒夜里看雪飘过
^怀着冷却了的心窝飘远方
""".trimMargin("^")
println(txt2)
println("----------------")
// 定义原始字符串
val txt3 = """真的爱你
| 无法可修饰的一对手
^ 带出温暖永远在背后
$ 纵使啰嗦始终关注不懂珍惜太内疚
"""
println(txt3)
}
输出:
长度为:11
----------------
无聊望见了犹豫
达到理想不太易
即使有信心
斗志却抑制
----------------
海阔天空
今天我
寒夜里看雪飘过
怀着冷却了的心窝飘远方
----------------
真的爱你
| 无法可修饰的一对手
^ 带出温暖永远在背后
$ 纵使啰嗦始终关注不懂珍惜太内疚
kotlin 原始字符串,用 3 个引号引起来的部分都是字符串内容,包括换行符等各种特殊字符。
编程时考虑到程序格式,往往会在原始字符串中进行一些缩进,但这些缩进并不是原始字 符串希望包含的,此时即可使用 trimMargin() 方法来去掉原始字符串前面的缩进一一在默认情况下, kotlin 使用竖线(|)作为边界符。也就是说,所有竖线(|)之前的内容都会被去掉。
如果有必要,开发者也可使用其他字符作为边界符, 此时就需要在 trimMargin() 方法中传入该边界符作为参数。比如示例中传入了 “^”
2 字符串模板
kotlin 允许在字符串中嵌入变量或表达式,只要将变量或表达式放入 ${} 中即可,这样 kotlin 将会把该变量或表达式的值嵌入该字符串中。
fun main(args: Array<String>) {
val bookPrice = 79
// 在字符串模板中嵌入变量
var s = "图书价格是:${bookPrice}"
println(s)
val rand = java.util.Random() // 创建 Java 的 Random对象
// 在字符串模板中嵌入方法调用
var s2 = "伪随机数是:${rand.nextInt(10)}"
println(s2)
val myStr = "flutter"
println("${myStr}的长度是:${myStr.length}")
var bookName = "金瓶梅"
val poem = """
|图书名是${bookName},
|图书价格是${bookPrice},
|图书售价是${rand.nextInt(10) + 50}
""".trimMargin()
println(poem)
}
输出:
图书价格是:79
伪随机数是:2
flutter的长度是:7
图书名是金瓶梅,
图书价格是79,
图书售价是50
3 字符串方法
Kotlin 的 String 与 Java 的 String 并不是同一个类,因此它们的方法略有不同,但是这两个类所提供的功能大致相似。实际上, Kotlin 的 String 类提供了更多的方法,如提供了 一系列 toXxx() 方法将字符串转换成数值。
3.1 字符串转换
fun main(args: Array<String>) {
val s1 = "2.34"
// 将 sl 字符串转换成 Double 类型
val d: Double = s1.toDouble()
println(d)
var s2 = "45"
// 将 s2 字符串转换成 Int 类型
var i: Int = s2.toInt()
println(i)
val str = "tencent.com"
println(str.capitalize()); // 首字母大写
println(str.decapitalize()); // 首字母小写
var str2 = "360.com"
// 返回两个字符串相同的前缀
println(str2.commonPrefixWith("360"));
// 返回两个字符串相同的后缀
println(str2.commonSuffixWith("com"));
var str3 = "java886"
// 判断 str3 是否包含 3 个连续的数字
println(str3.contains(Regex("\\d{3}")))
}
输出:
2.34
45
Tencent.com
tencent.com
360
com
true
3.2 字符串查找
fun main(args: Array<String>) {
val sourceStr = "There is a string accessing example."
val len = sourceStr.length //获得字符串长度
val ch = sourceStr[16] //获得索引位置16的字符
//查找字符和子字符串
val firstChar1 = sourceStr.indexOf('r')
val lastChar1 = sourceStr.lastIndexOf('r', ignoreCase = true)
val firstStr1 = sourceStr.indexOf("ing")
val lastStr1 = sourceStr.lastIndexOf("ing")
val firstChar2 = sourceStr.indexOf('e', 15)
val lastChar2 = sourceStr.lastIndexOf('e', 15)
val firstStr2 = sourceStr.indexOf("ing", 5)
val lastStr2 = sourceStr.lastIndexOf("ing", 5)
println("原始字符串:" + sourceStr)
println("字符串长度:" + len)
println("索引16的字符:" + ch)
println("从前往后查找r字符,第一次找到它所在索引:" + firstChar1)
println("从后往前查找r字符,第一次找到它所在索引:" + lastChar1)
println("从前往后查找ing字符串,第一次找到它所在索引:" + firstStr1)
println("从后往前查找ing字符串,第一次找到它所在索引:" + lastStr1)
println("从索引为15位置开始,从前往后查找e字符,第一次找到它所在索引:" + firstChar2)
println("从索引为15位置开始,从后往前查找e字符,第一次找到它所在索引:" + lastChar2)
println("从索引为5位置开始,从前往后查找ing字符串,第一次找到它所在索引:" + firstStr2)
println("从索引为5位置开始,从后往前查找ing字符串,第一次找到它所在索引:" + lastStr2)
}
输出:
原始字符串:There is a string accessing example.
字符串长度:36
索引16的字符:g
从前往后查找r字符,第一次找到它所在索引:3
从后往前查找r字符,第一次找到它所在索引:13
从前往后查找ing字符串,第一次找到它所在索引:14
从后往前查找ing字符串,第一次找到它所在索引:24
从索引为15位置开始,从前往后查找e字符,第一次找到它所在索引:21
从索引为15位置开始,从后往前查找e字符,第一次找到它所在索引:4
从索引为5位置开始,从前往后查找ing字符串,第一次找到它所在索引:14
从索引为5位置开始,从后往前查找ing字符串,第一次找到它所在索引:-1
3.3 字符串比较
fun main(args: Array<String>) {
val s1 = "Hello"
val s2 = "Hello"
// 比较字符串内容是否相等
println(s1.equals(s2)) //输出true
println(s1 == s2) //输出true
val s3 = "HELlo"
// 忽略大小写比较字符串内容是否相等
println(s1.equals(s3, ignoreCase = true)) //输出true
println(s1 == s3) //输出false
// 比较大小
val s4 = "java"
val s5 = "Kotlin"
println(s4.compareTo(s5)) // 输出31
println(s4.compareTo(s5, ignoreCase = true)) // 输出-1
// 判断文件夹中文件名
val docFolder = arrayOf("java.docx", "JavaBean.docx", "Objecitve-C.xlsx", "Swift.docx ")
var wordDocCount = 0
// 查找文件夹中Word文档个数
for (doc in docFolder) {
// 比较后缀是否有.docx字符串
if (doc.endsWith(".docx")) {
wordDocCount++
}
}
println("文件夹中Word文档个数是: " + wordDocCount) // 输出 文件夹中Word文档个数是: 2
var javaDocCount = 0
// 查找文件夹中Java相关文档个数
for (doc in docFolder) {
// 比较前缀是否有java字符串
if (doc.startsWith("java", ignoreCase = true)) {
javaDocCount++
}
}
println("文件夹中Java相关文档个数是:" + javaDocCount) // 输出 文件夹中Java相关文档个数是:2
}
3.4 字符串截取
fun main(args: Array<String>) {
val sourceStr = "There is a string accessing example."
// 截取example.子字符串
val subStr1 = sourceStr.substring(28) // 输出 example.
// 截取string子字符串
val subStr2 = sourceStr.substring(11, 17) // 输出 string
println(subStr1)
println(subStr2)
}
3.5 可变字符串 StringBuilder
Kotlin 提供可变字符串类是 kotlin.text.StringBuilder,可变字符串在追加、删除、修改、插入和拼接等操作不会产生新的对象。
fun main(args: Array<String>) {
// 字符串长度length和字符串缓冲区容量capacity
val sb1 = StringBuilder()
println("字符串长度:" + sb1.length) // 输出:字符串长度:0
println("字符串容量:" + sb1.capacity()) // 输出:字符串容量:16
val sb2 = StringBuilder("Hello")
println("字符串长度:" + sb2.length) // 输出:字符串长度:5
println("字符串容量:" + sb2.capacity()) // 输出:字符串容量:21
// 字符串缓冲区初始容量是16,超过之后会扩容
val sb3 = StringBuilder()
for (i in 0..16) {
sb3.append(8)
}
println("字符串长度:" + sb3.length) // 输出:字符串长度:17
println("字符串容量:" + sb3.capacity()) // 输出:字符串容量:34
}
字符串追加、插入、删除和替换
fun main(args: Array<String>) {
//添加字符串、字符
val sb1 = StringBuilder("Hello")
sb1.append(" ").append("World")
sb1.append('.')
println(sb1) // 输出:Hello World.
val sb2 = StringBuilder()
val obj: Any? = null
//添加布尔值、转义符和空对象
sb2.append(false).append('\t').append(obj)
println(sb2) // 输出:false null
//添加数值
val sb3 = StringBuilder()
for (i in 0..9) {
sb3.append(i)
}
println(sb3) // 输出:0123456789
// 插入字符串
sb3.insert(4, "Kotlin")
println(sb3) // 输出:0123Kotlin456789
// 删除字符串
sb3.delete(1, 2)//删除"1"字符
println(sb3) // 输出:023Kotlin456789
// 删除替换字符串
sb3.replace(3, 9, "A") // "A"替换"Kotlin"
println(sb3) // 输出:023A456789
}
4 类型别名
Kotlin 提供了类似于 C 语言中的 typedef 的功能 : 可以为己有的类型指定另一个可读性更 强的名字。 Kotlin 提供了 typealias 来定义类型别名。 typealias 语句的语法格式为 :
typealias 类型别名=已有类型
如果类型名太长,我们可以使用较短的新名称来替代原类型名。这样有助于缩短较长的泛型类型。例如,通常缩短集合类型是很有吸引力的。
//为 Set<Network . Node>指定更短的别名: NodeSet
typealias NodeSet = Set<Network.Node>
//为 MutableMap<K, MutableList<File>指定更短的别名: FileTable<K>
typealias FileTable<K> = MutableMap<K, MutableList<File>>
接下来即可直接使用 NodeSet 和 FileTable命名变量。
var set: NodeSet
var table: FileTable<String>
很多时候,我们也可以通过定义别名为内部类起一个更短的名字。例如如下程序。
class A {
inner class Inner
}
class B {
inner class Inner
}
// 为 A.Inner 内部类指定别名
typealias AInner = A.Inner
// 为 B.Inner 内部类指定别名
typealias BInner = B.Inner
// 为(T)→ Boolean 类型指定别名 Predicate<T>
typealias Predicate<T> = (T) -> Boolean
fun main(args: Array<String>) {
// 使用 AInner 定义变量、调用对象
var a: AInner = A().AInner()
// 使用 BInner 定义变盘、调用对象
var b = B().BInner()
// 使用 Predicate<String>定义变量, 该变量的值是一个 Lambda 表达式
val p: Predicate<String> = { it.length > 4 }
// 为 filter ()方法传入 p 参数,只保留长度大于 4 的字符串
println(arrayOf("Java", "Objective-C", "Go", "Kotlin").filter(p))
}
上面程序中为 A.Inner、B.Inner 两个内部类分别指定了别名 AInner和 BInner , 接下来程序即可使用 Alnner、 Blnner 别名类定义变量、创建对象。
此外, kotlin 自己也大量利用了别名这个功能。比如 kotlin 利用别名建立了 kotlin 类和 Java 类之间的关系 。如下代码是 kotlin 集合体系中定义的别名。
typealias kotlin.ArrayList<E> = java.util.ArrayList<E>
typealias kotlin.HashMap<K, V> = java.util.HashMap<K, V>
typealias kotlin.HashSet<E> = java.util.HashSet<E>
typealias kotlin.LinkedHashMap<K, V> = java.util.LinkedHashMap<K, V>
typealias kotlin.LinkedHashSet<E> = java.util.LinkedHashSet<E>