字符串常用的操作符
commonPrefixWith
返回两个字符串中最长的相同前缀,如果它们没有共同的前缀,则返回空字符串,可以定义 ignoreCase 为 true 忽略大小写
val action = "蔡徐坤唱跳rap" val time = "蔡徐坤两年半" val introduce = "个人练习生蔡徐坤喜欢唱跳rap" println(action.commonPrefixWith(time)) // 蔡徐坤 println(action.commonPrefixWith(introduce)) // ""
源码实现
// 通过while获取两个字符串同个索引下的字符是否相等 // 最后通过subSequence切割字符串 public fun CharSequence.commonPrefixWith(other: CharSequence, ignoreCase: Boolean = false): String { val shortestLength = minOf(this.length, other.length) var i = 0 while (i < shortestLength && this[i].equals(other[i], ignoreCase = ignoreCase)) { i++ } if (this.hasSurrogatePairAt(i - 1) || other.hasSurrogatePairAt(i - 1)) { i-- } return subSequence(0, i).toString() }
commonSuffixWith
返回两个字符串中最长的相同后缀,如果它们没有共同的后缀,则返回空字符串,可以定义 ignoreCase 为 true 忽略大小写
val action = "蔡徐坤唱跳rap" val time = "蔡徐坤两年半" val introduce = "个人练习生蔡徐坤喜欢唱跳rap" println(action.commonSuffixWith(time)) println(action.commonSuffixWith(introduce))
源码实现
// 与commonPrefixWith的实现差不多,只是commonSuffixWith是倒序循环 public fun CharSequence.commonSuffixWith(other: CharSequence, ignoreCase: Boolean = false): String { val thisLength = this.length val otherLength = other.length val shortestLength = minOf(thisLength, otherLength) var i = 0 while (i < shortestLength && this[thisLength - i - 1].equals(other[otherLength - i - 1], ignoreCase = ignoreCase)) { i++ } if (this.hasSurrogatePairAt(thisLength - i - 1) || other.hasSurrogatePairAt (otherLength - i - 1)) { i-- } return subSequence(thisLength - i, thisLength).toString() }
contains
判断字符串是否包含某字符或某字符串,可以定义 ignoreCase 为 true 忽略大小写
val introduce = "个人练习生蔡徐坤喜欢唱跳rap" println(introduce.contains('唱')) // true println(introduce.contains("蔡徐坤")) // true println("蔡徐坤" in introduce) // // 同上,contains是重载操作符,可以使用该表达式 println(introduce.contains("Rap", ignoreCase = true)) // true println("Rap" !in introduce) // !in表示不包含的意思,与!introduce.contains("Rap")是同个意思
源码实现
// 通过indexOf判断字符是否存在 public operator fun CharSequence.contains(char: Char, ignoreCase: Boolean = false): Boolean = indexOf(char, ignoreCase = ignoreCase) >= 0 // 通过indexOf判断字符串是否存在 public operator fun CharSequence.contains(other: CharSequence, ignoreCase: Boolean = false): Boolean = if (other is String) indexOf(other, ignoreCase = ignoreCase) >= 0 else indexOf(other, 0, length, ignoreCase) >= 0
endsWith
判断字符串是否以某字符或某字符串作为后缀,可以定义 ignoreCase 为 true 忽略大小写
val introduce = "个人练习生蔡徐坤喜欢唱跳rap" println(introduce.endsWith("蔡徐坤")) // false println(introduce.endsWith("唱跳rap")) // true
源码实现
// 字符直接判断最末尾的字符 public fun CharSequence.endsWith(char: Char, ignoreCase: Boolean = false): Boolean = this.length > 0 && this[lastIndex].equals(char, ignoreCase) // 如果都是String,返回String.endsWith,否则返回regionMatchesImpl public fun CharSequence.endsWith(suffix: CharSequence, ignoreCase: Boolean = false): Boolean { if (!ignoreCase && this is String && suffix is String) return this.endsWith(suffix) else return regionMatchesImpl(length - suffix.length, suffix, 0, suffix.length, ignoreCase) } // 不忽略大小写,返回java.lang.String.endsWith public actual fun String.endsWith(suffix: String, ignoreCase: Boolean = false): Boolean { if (!ignoreCase) return (this as java.lang.String).endsWith(suffix) else return regionMatches(length - suffix.length, suffix, 0, suffix.length, ignoreCase = true) }
equals
判断两个字符串的值是否相等,可以定义 ignoreCase 为 true 忽略大小写
val introduce = "蔡徐坤rap" println(introduce.equals("蔡徐坤Rap")) // false println(introduce == "蔡徐坤Rap") // 同上,因为equals是重载操作符,通常使用 == 表示即可 println(introduce.equals("蔡徐坤Rap", false)) // true
源码实现
// 通过java.lang.String的equals和equalsIgnoreCase判断 public actual fun String?.equals(other: String?, ignoreCase: Boolean = false): Boolean { if (this === null) return other === null return if (!ignoreCase) (this as java.lang.String).equals(other) else (this as java.lang.String).equalsIgnoreCase(other) }
ifBlank
如果字符串都是空格,将字符串转成默认值。这个操作符非常有用
val whitespace = " ".ifBlank { "default" } val introduce = "蔡徐坤rap".ifBlank { "default" } println(whitespace) // default println(introduce) // 蔡徐坤rap
源码实现
public inline fun <C, R> C.ifBlank(defaultValue: () -> R): R where C : CharSequence, C : R = if (isBlank()) defaultValue() else this
ifEmpty
如果字符串都是空字符串,将字符串转成默认值。这个操作符非常有用,省去了你去判断空字符串然后再次赋值的操作
val whitespace = " ".ifEmpty { "default" } val empty = "".ifEmpty { "default" } val introduce = "蔡徐坤rap".ifEmpty { "default" } println(whitespace) // " " println(empty) // default println(introduce) // 蔡徐坤rap
判断空字符串、null 和空格字符串
isEmpty 判断空字符串
isBlank 判断字符串都是空格
isNotBlank 与 isBlank 相反,判断字符串不是空格
isNotEmpty 与 isEmpty 相反,判断字符串不是空格
isNullOrBlank 判断字符串不是 null 和 空格
isNullOrEmpty 判断字符串不是 null 和 空字符串
lines
将字符串以换行符或者回车符进行分割,返回每一个分割的子字符串 List<String>
val article = "大家好我是练习时长两年半的个人练习生\n蔡徐坤\r喜欢唱跳rop" println(article.lines()) // [大家好我是练习时长两年半的个人练习生, 蔡徐坤, 喜欢唱跳rop]
源码实现
// 大概就是通过Sequence去切割字符串 public fun CharSequence.lines(): List<String> = lineSequence().toList() public fun CharSequence.lineSequence(): Sequence<String> = splitToSequence("\r\n", "\n", "\r") public fun <T> Sequence<T>.toList(): List<T> { return this.toMutableList().optimizeReadOnlyList() }
lowercase
将字符串都转换成小写
val introduce = "蔡徐坤RaP" println(introduce.lowercase()) // 蔡徐坤rap
源码实现
// 通过java.lang.String的toLowerCase方法实现,其实很多kotlin的方法都是调用java的啦 public actual inline fun String.lowercase(): String = (this as java.lang.String).toLowerCase(Locale.ROOT)
replace
将字符串内的某一部分替换为新的值,可以定义 ignoreCase 为 true 忽略大小写
val introduce = "蔡徐坤rap" println(introduce.replace("rap", "RAP")) println(introduce.replace("raP", "RAP", ignoreCase = true))
源码实现
// 首先通过indexOf判断是否存在要被替换的子字符串 // do while循环添加被替换之后的字符串,因为字符串有可能是有多个地方需要替换, 所有通过occurrenceIndex判断是否还有需要被替换的部分 public actual fun String.replace(oldValue: String, newValue: String, ignoreCase: Boolean = false): String { run { var occurrenceIndex: Int = indexOf(oldValue, 0, ignoreCase) // FAST PATH: no match if (occurrenceIndex < 0) return this val oldValueLength = oldValue.length val searchStep = oldValueLength.coerceAtLeast(1) val newLengthHint = length - oldValueLength + newValue.length if (newLengthHint < 0) throw OutOfMemoryError() val stringBuilder = StringBuilder(newLengthHint) var i = 0 do { stringBuilder.append(this, i, occurrenceIndex).append(newValue) i = occurrenceIndex + oldValueLength if (occurrenceIndex >= length) break occurrenceIndex = indexOf(oldValue, occurrenceIndex + searchStep, ignoreCase) } while (occurrenceIndex > 0) return stringBuilder.append(this, i, length).toString() } }
startsWith
判断字符串是否以某字符或某字符串作为前缀,可以定义 ignoreCase 为 true 忽略大小写
val introduce = "rap" println(introduce.startsWith("Rap")) println(introduce.startsWith("Rap", ignoreCase = true))
源码实现
// 还是调用的java.lang.String的startsWith public actual fun String.startsWith(prefix: String, ignoreCase: Boolean = false): Boolean { if (!ignoreCase) return (this as java.lang.String).startsWith(prefix) else return regionMatches(0, prefix, 0, prefix.length, ignoreCase) }
substringAfter
获取分割符之后的子字符串,如果不存在该分隔符默认返回原字符串,当然你可以自定义返回
例如在截取 ip:port 格式的时候,分隔符就是 :
val ipAddress = "192.168.1.1:8080" println(ipAddress.substringAfter(":")) // 8080 println(ipAddress.substringAfter("?")) // 192.168.1.1:8080 println(ipAddress.substringAfter("?", missingDelimiterValue = "没有?这个子字符串")) // 没有?这个子字符串
源码实现
// 还是通过substring来截取字符串的 public fun String.substringAfter(delimiter: String, missingDelimiterValue: String = this): String { val index = indexOf(delimiter) return if (index == -1) missingDelimiterValue else substring (index + delimiter.length, length) }
substringAfterLast
与 substringAfter 是同一个意思,不同的是如果一个字符串中有多个分隔符,substringAfter 是从第一个开始截取字符串,substringAfterLast 是从最后一个分隔符开始截取字符串
val network = "255.255.255.0:192.168.1.1:8080" println(network.substringAfter(":")) // 192.168.1.1:8080 println(network.substringAfterLast(":")) // 8080
源码实现
// 源码和substringAfter差不多,只是substringAfterLast获取的是最后一个分割符的索引 public fun String.substringAfterLast(delimiter: String, missingDelimiterValue: String = this): String { val index = lastIndexOf(delimiter) return if (index == -1) missingDelimiterValue else substring (index + delimiter.length, length) }
substringBefore
获取分割符之前的子字符串,如果不存在该分隔符默认返回原字符串,当然你可以自定义返回,与 substringAfter 刚好相反
val ipAddress = "192.168.1.1:8080" println(ipAddress.substringBefore(":")) // 192.168.1.1 println(ipAddress.substringBefore("?")) // 192.168.1.1:8080 println(ipAddress.substringBefore("?", missingDelimiterValue = "没有?这个子字符串")) // 没有?这个子字符串
源码实现
// 还是通过substring来截取字符串的,只是是从索引0开始截取子字符串 public fun String.substringBefore(delimiter: String, missingDelimiterValue: String = this): String { val index = indexOf(delimiter) return if (index == -1) missingDelimiterValue else substring(0, index) }
substringBeforeLast
与 substringBefore 是同一个意思,不同的是如果一个字符串中有多个分隔符,substringBefore 是从第一个开始截取字符串,substringBeforeLast 是从最后一个分隔符开始截取字符串
val network = "255.255.255.0:192.168.1.1:8080" println(network.substringBefore(":")) // 255.255.255.0 println(network.substringBeforeLast(":")) // 255.255.255.0:192.168.1.1
源码实现
// 源码和substringBefore差不多,只是substringBeforeLast获取的是最后一个分割符的索引 public fun String.substringBeforeLast(delimiter: String, missingDelimiterValue: String = this): String { val index = lastIndexOf(delimiter) return if (index == -1) missingDelimiterValue else substring(0, index) }
trim
去掉字符串首尾的空格符,如果要去掉字符串中间的空格符请用 replace
val introduce = " 个人练习生蔡徐坤 喜欢唱跳rap " println(introduce.trim()) // 个人练习生蔡徐坤 喜欢唱跳rap
uppercase
将字符串都转换成大写
源码实现
// java.lang.String.toUpperCase public actual inline fun String.uppercase(): String = (this as java.lang.String).toUpperCase (Locale.ROOT)
发表评论 取消回复