All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.xml.guard.utils.StringUtil.kt Maven / Gradle / Ivy

package com.xml.guard.utils

import org.gradle.api.Project
import java.io.File
import kotlin.math.pow
import kotlin.random.Random

/**
 * User: ljx
 * Date: 2022/3/1
 * Time: 17:31
 */
private const val LETTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
private const val LETTERS_AND_NUMBERS = LETTERS + "0123456789"

/**
 * 判断字符是否为小写,排除掉数字
 */
fun String?.isLowercase(): Boolean {
    return this?.filter { !it.isDigit() }?.all { it.isLowerCase() } ?: false
}

fun String.replaceLast(oldValue: String, newValue: String): String {
    val index = lastIndexOf(oldValue)
    return if (index == -1) this else substring(0, index) + newValue
}

// 移除后缀
fun String.removeSuffix(): String {
    val index = lastIndexOf(".")
    return if (index == -1) this else substring(0, index)
}

// 获取后缀
fun String.getSuffix(): String {
    val index = lastIndexOf(".")
    return if (index == -1) "" else substring(index)
}

fun String.getDirPath(): String {
    val index = lastIndexOf(".")
    return if (index == -1) this else substring(0, index)
}

fun String.getClassName(): String {
    val index = lastIndexOf(".")
    return if (index == -1) this else substring(index + 1)
}

// 获取类文件包名
fun getClassPackage(project: Project, file: File): String {
    val srcMainPath = project.file("src${File.separator}main").absolutePath + File.separator
    val filePath = file.absolutePath
    var rawPackage = filePath.replace(srcMainPath, "")
        .replaceBefore(File.separator, "")
        .replaceAfterLast(File.separator, "")

    var startIndex = rawPackage.indexOf(File.separator)
    startIndex = if (startIndex != -1) startIndex + 1 else 0

    var endIndex = rawPackage.lastIndexOf(File.separator)
    endIndex = if (endIndex != -1) endIndex else rawPackage.length

    rawPackage = rawPackage.substring(startIndex, endIndex)
        .replace(File.separator, ".")
    return rawPackage.trim()
}

// 文件名转为驼峰形式
fun String.convertToCamelCase(): String {
    // 假设文件名可能包含下划线、连字符、点或空格作为分隔符
    val words = this.split("_", "-", ".", " ")
    val camelCaseBuilder = StringBuilder()
    for (word in words) {
        if (word.isNotBlank()) {
            // 将单词的首字母大写并追加到结果中
            camelCaseBuilder.append(word.uppercaseFirstChar())
        }
    }
    return camelCaseBuilder.toString()
}

// 首字母小写
fun String.lowercaseFirstChar(): String {
    return this.replaceFirstChar { it.lowercase() }
}

// 首字母大写
fun String.uppercaseFirstChar(): String {
    return this.replaceFirstChar { if (it.isLowerCase()) it.titlecase() else it.toString() }
}

// 获取 layout 布局所对应的 Binding 名称
fun String.getLayoutBindingName(): String {
    return this.convertToCamelCase() + "Binding"
}

fun String.findWord(
    word: String,
    ignoreCase: Boolean = false
): Int {
    var occurrenceIndex = indexOf(word, 0, ignoreCase)
    // FAST PATH: no match
    if (occurrenceIndex < 0) return -1

    val oldValueLength = word.length
    val searchStep = oldValueLength.coerceAtLeast(1)

    do {
        if (isWord(occurrenceIndex, word)) {
            return occurrenceIndex
        }
        if (occurrenceIndex >= length) break
        occurrenceIndex = indexOf(word, occurrenceIndex + searchStep, ignoreCase)
    } while (occurrenceIndex > 0)
    return -1
}

fun String.replaceWordsByPattern(oldValue: String, newValue: String): String {
    // \b 表示单词边界
    val matcher = "\\b${oldValue}\\b".toPattern().matcher(this)
    return matcher.replaceAll(newValue)
}

fun String.replaceWords(
    oldValue: String,
    newValue: String,
    ignoreCase: Boolean = false
): String {
    var occurrenceIndex = 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 {
        if (isWord(occurrenceIndex, oldValue)) {
            stringBuilder.append(this, i, occurrenceIndex).append(newValue)
        } else {
            stringBuilder.append(this, i, occurrenceIndex + oldValueLength)
        }
        i = occurrenceIndex + oldValueLength
        if (occurrenceIndex >= length) break
        occurrenceIndex = indexOf(oldValue, occurrenceIndex + searchStep, ignoreCase)
    } while (occurrenceIndex > 0)
    return stringBuilder.append(this, i, length).toString()
}

fun String.isWord(index: Int, oldValue: String): Boolean {
    val firstChar = oldValue[0].code
    if (index > 0 && (firstChar in 65..90 || firstChar == 95 || firstChar in 97..122)) {
        val prefix = get(index - 1).code
        // $ . 0-9 A-Z _ a-z
        if (prefix == 36 || prefix == 46 || prefix in 48..57 || prefix in 65..90 || prefix == 95 || prefix in 97..122) {
            return false
        }
    }
    val endChar = oldValue[oldValue.lastIndex].code
    // $ 0-9 A-Z _ a-z
    if (endChar == 36 || endChar in 48..57 || endChar in 65..90 || endChar == 95 || endChar in 97..122) {

        val suffix = getOrNull(index + oldValue.length)?.code
        // $ 0-9 A-Z _ a-z
        if (suffix == 36 || suffix in 48..57 || suffix in 65..90 || suffix == 95 || suffix in 97..122) {
            return false
        }
    }
    return true
}

// 字符串随机转换大小写
fun String.randomizeCase(): String {
    return this.map {
        if (Random.nextBoolean()) {
            it.uppercaseChar()
        } else {
            it.lowercaseChar()
        }
    }.joinToString("")
}

/**
 * 获取随机字符,该字符长度均匀分布在指定的 [from](含)和 [until](不包括)边界之间。
 *
 * @param filter 用于字符过滤处理;若返回为空则重新生成字符
 */
fun getRandomString(
    from: Int = 2,
    until: Int = 7,
    onlyLetter: Boolean = false,
    filter: (text: String) -> String?
): String {
    val length = Random.nextInt(from, until)
    val builder = StringBuilder()

    while (true) {
        if (builder.isNotBlank()) {
            builder.clear()
        }

        // 确保首字符为字母
        builder.append(LETTERS.random())

        // 生成剩余字符
        val source = if (onlyLetter) LETTERS else LETTERS_AND_NUMBERS
        for (i in 1 until length) {
            builder.append(source.random())
        }

        val text = builder.toString()
        val result = filter.invoke(text)
        if (result?.isNotBlank() == true && !result.inBlackList()) {
            return result
        }
    }
}

// 是否在黑名单
fun String.inBlackList(): Boolean {
    return this.inPackageNameBlackList() || this.inClassNameBlackList()
}

// Long 转 大写字符串
fun Long.toUpperLetterStr(): String {
    return toLetterStr(true)
}

// Long 转 大/小字符串
fun Long.toLetterStr(upperCase: Boolean = false): String {
    val size = 26
    val offSize = if (upperCase) 65 else 97
    val sb = StringBuilder()
    var num = this
    do {
        val char = (num % size + offSize).toInt().toChar()
        sb.append(char)
        num /= size
    } while (num > 0)
    return sb.reverse().toString()
}

// 字符串转Long
@Suppress("CheckResult")
fun String.to26Long(): Long {
    val length = length
    var num = 0L
    for (i in 0 until length) {
        val c = get(i)
        val offSize = if (c.isUpperCase()) 65 else 97
        num += ((c.code - offSize) * 26.0.pow((length - 1 - i).toDouble())).toLong()
    }
    return num
}

internal fun String.splitWords(): List {
    val regex = Regex("(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])")
    return split(regex).map { it.lowercase() }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy