字符串常用的操作符

commonPrefixWith

回来两个字符串中最长的相同前缀,假如它们没有一起的前缀,则回来空字符串,能够界说 ignoreCasetrue 疏忽大小写

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

回来两个字符串中最长的相同后缀,假如它们没有一起的后缀,则回来空字符串,能够界说 ignoreCasetrue 疏忽大小写

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

判别字符串是否包含某字符或某字符串,能够界说 ignoreCasetrue 疏忽大小写

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

判别字符串是否以某字符或某字符串作为后缀,能够界说 ignoreCasetrue 疏忽大小写

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

判别两个字符串的值是否持平,能够界说 ignoreCasetrue 疏忽大小写

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 判别字符串都是空格
  • isNotBlankisBlank 相反,判别字符串不是空格
  • 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

将字符串内的某一部分替换为新的值,能够界说 ignoreCasetrue 疏忽大小写

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

判别字符串是否以某字符或某字符串作为前缀,能够界说 ignoreCasetrue 疏忽大小写

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)