/* * Copyright 2026 mingliqiye * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ProjectName mingli-utils * ModuleName mingli-utils.main * CurrentFile StringUtils.kt * LastUpdate 2026-02-05 11:05:33 * UpdateUser MingLiPro */ @file:JvmName("StringUtils") package com.mingliqiye.utils.string import com.mingliqiye.utils.base.BASE16 import com.mingliqiye.utils.logger.MingLiLoggerFactory import com.mingliqiye.utils.objects.isNull import java.net.URLDecoder import java.net.URLEncoder import java.security.MessageDigest import javax.crypto.Mac import javax.crypto.spec.SecretKeySpec import kotlin.contracts.ExperimentalContracts import kotlin.contracts.contract private val log = MingLiLoggerFactory.getLogger(Class.forName("com.mingliqiye.utils.string.StringUtils")) val NULLISH_STRINGS = setOf("null", "NaN", "undefined", "None", "none") /** * 判断`字符串`是否为空 * * @param str 待判断的字符串 * @return `true`: 空 `false`: 非空 */ @OptIn(ExperimentalContracts::class) @JvmName("isEmpty") fun String?.isNullish(): Boolean { contract { returns(false) implies (this@isNullish != null) } return this.isNullOrBlank() || this in NULLISH_STRINGS } @JvmName("__Formatde") fun String.formatd(vararg args: Any) = com.mingliqiye.utils.string.format(this, *args) /** * 格式化字符串,将字符串中的占位符{}替换为对应的参数值 * * `Kotlin`语言给我老老实实用`$`啊 * * @param str 需要格式化的字符串,包含{}占位符 \\{} 代表一个{} * @param args 要替换占位符的参数列表 * @return 格式化后的字符串 */ fun format(str: String, vararg args: Any?): String { var argIndex = 0 val result = StringBuilder() var lastIndex = 0 // 匹配所有非转义的 {} val pattern = Regex("(? = unicode.split("\\\\u".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() // 从索引1开始遍历,因为分割后的第一个元素是转义符前面的内容(可能为空) for (i in 1.. { return str.split(separator) } /** * 将列表中的元素使用指定分隔符连接成字符串 * @param separator 连接分隔符 * @param getstring 转换函数,将列表元素转换为字符串,默认使用toString()方法 * @return 连接后的字符串 */ fun List.join(separator: String, getstring: (T) -> String = { it.toString() }): String { // 使用StringBuilder构建结果字符串 val sb = StringBuilder() for (i in this.indices) { sb.append(this[i]) // 除了最后一个元素外,都在后面添加分隔符 if (i != this.size - 1) { sb.append(separator) } } return sb.toString() } /** * 使用当前字符串作为分隔符,将列表中的元素连接成字符串 * @param list 需要连接的元素列表 * @param getstring 转换函数,将列表元素转换为字符串,默认使用toString()方法 * @return 连接后的字符串 */ fun String.join(list: List, getstring: (T) -> String = { it.toString() }): String { // 使用StringBuilder构建结果字符串 val sb = StringBuilder() for (i in list.indices) { sb.append(getstring(list[i])) // 除了最后一个元素外,都在后面添加当前字符串作为分隔符 if (i != list.size - 1) { sb.append(this) } } return sb.toString() } fun String.join(array: Array, getstring: (T) -> String = { it.toString() }): String { // 使用StringBuilder构建结果字符串 val sb = StringBuilder() for (i in array.indices) { sb.append(getstring(array[i])) // 除了最后一个元素外,都在后面添加当前字符串作为分隔符 if (i != array.size - 1) { sb.append(this) } } return sb.toString() } fun String?.parserTemplate(template: String): List? { if (this == null) return null val regex: Regex = Regex( "^" + template .replace("\\", "\\\\") .replace("(", "\\(") .replace(")", "\\)") .replace("[", "\\[") .replace("]", "\\]") .replace("+", "\\+") .replace("=", "\\=") .replace("{}", "((?s).*)") .toRegex() + "$" ) val datas = regex.find(this)?.groupValues ?: return null return List(datas.size - 1) { datas[it + 1] } } fun String.urlEncode() = URLEncoder.encode(this, Charsets.UTF_8.name()) fun String.urlDecode() = URLDecoder.decode(this, Charsets.UTF_8.name()) fun String.hmacSHA256String(keyS: String): String { val instance = Mac.getInstance("HmacSHA256") val key = keyS.toByteArray() instance.init(SecretKeySpec(key, 0, key.size, "HmacSHA256")) val bytes = instance.doFinal(this.toByteArray()) return BASE16.encode(bytes) } fun String.md5String(): String { val instance = MessageDigest.getInstance("MD5") instance.update(this.toByteArray()) val bytes = instance.digest() return BASE16.encode(bytes) } fun String.hmacMd5String(keyS: String): String { val instance = Mac.getInstance("HmacMD5") val key = keyS.toByteArray() instance.init(SecretKeySpec(key, 0, key.size, "HmacSHA256")) val bytes = instance.doFinal(this.toByteArray()) return BASE16.encode(bytes) }