495 lines
16 KiB
Kotlin
495 lines
16 KiB
Kotlin
package com.img.rabbit.utils
|
||
|
||
import android.text.TextUtils
|
||
import java.net.URLDecoder
|
||
import java.security.MessageDigest
|
||
import java.security.NoSuchAlgorithmException
|
||
import java.text.ParseException
|
||
import java.text.SimpleDateFormat
|
||
import java.util.Calendar
|
||
import java.util.GregorianCalendar
|
||
import java.util.Hashtable
|
||
import java.util.Locale
|
||
import java.util.UUID
|
||
import java.util.concurrent.ThreadLocalRandom
|
||
import java.util.regex.Matcher
|
||
import java.util.regex.Pattern
|
||
|
||
|
||
object StringUtils {
|
||
/**
|
||
* 功能:身份证的有效验证
|
||
*
|
||
* @param IDStr 身份证号
|
||
* @return 有效:返回"" 无效:返回String信息
|
||
* @throws ParseException
|
||
*/
|
||
@Throws(ParseException::class)
|
||
fun IDCardValidate(IDStr: String): Boolean {
|
||
var errorInfo = "" // 记录错误信息
|
||
val ValCodeArr = arrayOf(
|
||
"1", "0", "x", "9", "8", "7", "6", "5", "4",
|
||
"3", "2"
|
||
)
|
||
val Wi = arrayOf(
|
||
"7", "9", "10", "5", "8", "4", "2", "1", "6", "3", "7",
|
||
"9", "10", "5", "8", "4", "2"
|
||
)
|
||
var Ai = ""
|
||
// ================号码的长度 15位或18位 ================
|
||
if (IDStr.length != 15 && IDStr.length != 18) {
|
||
errorInfo = "身份证号码长度应该为15位或18位。"
|
||
return false
|
||
}
|
||
// =======================(end)========================
|
||
|
||
// ================ 数字 除最后以为都为数字================
|
||
if (IDStr.length == 18) {
|
||
Ai = IDStr.substring(0, 17)
|
||
} else if (IDStr.length == 15) {
|
||
Ai = IDStr.substring(0, 6) + "19" + IDStr.substring(6, 15)
|
||
}
|
||
if (isNumeric(Ai) == false) {
|
||
errorInfo = "身份证15位号码都应为数字 ; 18位号码除最后一位外,都应为数字。"
|
||
return false
|
||
}
|
||
// =======================(end)========================
|
||
|
||
// ================ 出生年月是否有效 ================
|
||
val strYear = Ai.substring(6, 10) // 年份
|
||
val strMonth = Ai.substring(10, 12) // 月份
|
||
val strDay = Ai.substring(12, 14) // 月份
|
||
if (isDataFormat("$strYear-$strMonth-$strDay") == false) {
|
||
errorInfo = "身份证生日无效。"
|
||
return false
|
||
}
|
||
val gc = GregorianCalendar()
|
||
val s = SimpleDateFormat("yyyy-MM-dd")
|
||
try {
|
||
if (gc[Calendar.YEAR] - strYear.toInt() > 150
|
||
|| gc.time.time - s.parse(
|
||
"$strYear-$strMonth-$strDay"
|
||
).time < 0
|
||
) {
|
||
errorInfo = "身份证生日不在有效范围。"
|
||
return false
|
||
}
|
||
} catch (e: NumberFormatException) {
|
||
// TODO Auto-generated catch block
|
||
e.printStackTrace()
|
||
} catch (e: ParseException) {
|
||
// TODO Auto-generated catch block
|
||
e.printStackTrace()
|
||
}
|
||
if (strMonth.toInt() > 12 || strMonth.toInt() == 0) {
|
||
errorInfo = "身份证月份无效"
|
||
return false
|
||
}
|
||
if (strDay.toInt() > 31 || strDay.toInt() == 0) {
|
||
errorInfo = "身份证日期无效"
|
||
return false
|
||
}
|
||
// =====================(end)=====================
|
||
|
||
// ================ 地区码时候有效================
|
||
val h = GetAreaCode()
|
||
if (h[Ai.substring(0, 2)] == null) {
|
||
errorInfo = "身份证地区编码错误。"
|
||
return false
|
||
}
|
||
// ==============================================
|
||
|
||
// ================ 判断最后一位的值================
|
||
var TotalmulAiWi = 0
|
||
for (i in 0..16) {
|
||
TotalmulAiWi = (TotalmulAiWi
|
||
+ Ai[i].toString().toInt() * Wi[i].toInt())
|
||
}
|
||
val modValue = TotalmulAiWi % 11
|
||
val strVerifyCode = ValCodeArr[modValue]
|
||
Ai = Ai + strVerifyCode
|
||
if (IDStr.length == 18) {
|
||
if (Ai == IDStr == false) {
|
||
errorInfo = "身份证无效,不是合法的身份证号码"
|
||
return false
|
||
}
|
||
} else {
|
||
return true
|
||
}
|
||
// =====================(end)=====================
|
||
return true
|
||
}
|
||
|
||
/**
|
||
* 功能:判断字符串是否为数字
|
||
*
|
||
* @param str
|
||
* @return
|
||
*/
|
||
private fun isNumeric(str: String): Boolean {
|
||
val pattern = Pattern.compile("[0-9]*")
|
||
val isNum = pattern.matcher(str)
|
||
return if (isNum.matches()) {
|
||
true
|
||
} else {
|
||
false
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 功能:设置地区编码
|
||
*
|
||
* @return Hashtable 对象
|
||
*/
|
||
private fun GetAreaCode(): Hashtable<String, String> {
|
||
val hashtable = Hashtable<String, String>()
|
||
hashtable["11"] = "北京"
|
||
hashtable["12"] = "天津"
|
||
hashtable["13"] = "河北"
|
||
hashtable["14"] = "山西"
|
||
hashtable["15"] = "内蒙古"
|
||
hashtable["21"] = "辽宁"
|
||
hashtable["22"] = "吉林"
|
||
hashtable["23"] = "黑龙江"
|
||
hashtable["31"] = "上海"
|
||
hashtable["32"] = "江苏"
|
||
hashtable["33"] = "浙江"
|
||
hashtable["34"] = "安徽"
|
||
hashtable["35"] = "福建"
|
||
hashtable["36"] = "江西"
|
||
hashtable["37"] = "山东"
|
||
hashtable["41"] = "河南"
|
||
hashtable["42"] = "湖北"
|
||
hashtable["43"] = "湖南"
|
||
hashtable["44"] = "广东"
|
||
hashtable["45"] = "广西"
|
||
hashtable["46"] = "海南"
|
||
hashtable["50"] = "重庆"
|
||
hashtable["51"] = "四川"
|
||
hashtable["52"] = "贵州"
|
||
hashtable["53"] = "云南"
|
||
hashtable["54"] = "西藏"
|
||
hashtable["61"] = "陕西"
|
||
hashtable["62"] = "甘肃"
|
||
hashtable["63"] = "青海"
|
||
hashtable["64"] = "宁夏"
|
||
hashtable["65"] = "新疆"
|
||
hashtable["71"] = "台湾"
|
||
hashtable["81"] = "香港"
|
||
hashtable["82"] = "澳门"
|
||
hashtable["91"] = "国外"
|
||
return hashtable
|
||
}
|
||
|
||
/**
|
||
* 验证日期字符串是否是YYYY-MM-DD格式
|
||
*
|
||
* @param str
|
||
* @return
|
||
*/
|
||
private fun isDataFormat(str: String): Boolean {
|
||
var flag = false
|
||
// String
|
||
// regxStr="[1-9][0-9]{3}-[0-1][0-2]-((0[1-9])|([12][0-9])|(3[01]))";
|
||
val regxStr =
|
||
"^((\\d{2}(([02468][048])|([13579][26]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])))))|(\\d{2}(([02468][1235679])|([13579][01345789]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|(1[0-9])|(2[0-8]))))))(\\s(((0?[0-9])|([1-2][0-3]))\\:([0-5]?[0-9])((\\s)|(\\:([0-5]?[0-9])))))?$"
|
||
val pattern1 = Pattern.compile(regxStr)
|
||
val isNo = pattern1.matcher(str)
|
||
if (isNo.matches()) {
|
||
flag = true
|
||
}
|
||
return flag
|
||
}
|
||
//2.判断字符串是否是邮箱:
|
||
/**
|
||
* 描述:是否是邮箱.
|
||
*
|
||
* @param str 指定的字符串
|
||
* @return 是否是邮箱:是为true,否则false
|
||
*/
|
||
fun isEmail(str: String): Boolean {
|
||
var isEmail = false
|
||
val expr = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$"
|
||
if (str.matches(expr.toRegex())) {
|
||
isEmail = true
|
||
}
|
||
return isEmail
|
||
}
|
||
//3.判断字符串是否是银行卡
|
||
/**
|
||
* 判断是否是银行卡号
|
||
*
|
||
* @param cardId
|
||
* @return
|
||
*/
|
||
fun checkBankCard(cardId: String): Boolean {
|
||
val bit = getBankCardCheckCode(
|
||
cardId
|
||
.substring(0, cardId.length - 1)
|
||
)
|
||
return if (bit == 'N') {
|
||
false
|
||
} else cardId[cardId.length - 1] == bit
|
||
}
|
||
|
||
private fun getBankCardCheckCode(nonCheckCodeCardId: String?): Char {
|
||
if (nonCheckCodeCardId == null || nonCheckCodeCardId.trim { it <= ' ' }.length == 0 || !nonCheckCodeCardId.matches("\\d+".toRegex())) {
|
||
// 如果传的不是数据返回N
|
||
return 'N'
|
||
}
|
||
val chs = nonCheckCodeCardId.trim { it <= ' ' }.toCharArray()
|
||
var luhmSum = 0
|
||
var i = chs.size - 1
|
||
var j = 0
|
||
while (i >= 0) {
|
||
var k = chs[i].code - '0'.code
|
||
if (j % 2 == 0) {
|
||
k *= 2
|
||
k = k / 10 + k % 10
|
||
}
|
||
luhmSum += k
|
||
i--
|
||
j++
|
||
}
|
||
return if (luhmSum % 10 == 0) '0' else (10 - luhmSum % 10 + '0'.code).toChar()
|
||
}
|
||
//4、判断字符串是否是手机号
|
||
/**
|
||
* 判断是否是手机号
|
||
*
|
||
* @param phone
|
||
* @return
|
||
*/
|
||
fun checkPhone(phone: String?): Boolean {
|
||
val pattern = Pattern
|
||
.compile("^(13[0-9]|15[0-3]|15[5-9]|18[0-9]|14[57]|17[0678])\\d{8}$")
|
||
val matcher = pattern.matcher(phone)
|
||
return if (matcher.matches()) {
|
||
true
|
||
} else false
|
||
}
|
||
//5.判断字符串是否是中文或者包含中文
|
||
/**
|
||
* 描述:判断一个字符串是否为null或空值.
|
||
*
|
||
* @param str 指定的字符串
|
||
* @return true or false
|
||
*/
|
||
fun isEmpty(str: String?): Boolean {
|
||
return str == null || str.trim { it <= ' ' }.length == 0
|
||
}
|
||
|
||
/**
|
||
* 描述:是否是中文.
|
||
*
|
||
* @param str 指定的字符串
|
||
* @return 是否是中文:是为true,否则false
|
||
*/
|
||
fun isChinese(str: String): Boolean {
|
||
var isChinese = true
|
||
val chinese = "[\u0391-\uFFE5]"
|
||
if (!isEmpty(str)) {
|
||
//获取字段值的长度,如果含中文字符,则每个中文字符长度为2,否则为1
|
||
for (i in 0 until str.length) {
|
||
//获取一个字符
|
||
val temp = str.substring(i, i + 1)
|
||
//判断是否为中文字符
|
||
if (temp.matches(chinese.toRegex())) {
|
||
} else {
|
||
isChinese = false
|
||
}
|
||
}
|
||
}
|
||
return isChinese
|
||
}
|
||
|
||
/**
|
||
* 描述:是否包含中文.
|
||
*
|
||
* @param str 指定的字符串
|
||
* @return 是否包含中文:是为true,否则false
|
||
*/
|
||
fun isContainChinese(str: String): Boolean {
|
||
var isChinese = false
|
||
val chinese = "[\u0391-\uFFE5]"
|
||
if (!isEmpty(str)) {
|
||
//获取字段值的长度,如果含中文字符,则每个中文字符长度为2,否则为1
|
||
for (i in 0 until str.length) {
|
||
//获取一个字符
|
||
val temp = str.substring(i, i + 1)
|
||
//判断是否为中文字符
|
||
if (temp.matches(chinese.toRegex())) {
|
||
isChinese = true
|
||
} else {
|
||
}
|
||
}
|
||
}
|
||
return isChinese
|
||
}
|
||
|
||
/**
|
||
* 比较两个String的list 是否改变过
|
||
*
|
||
* @param listNew
|
||
* @param listOld
|
||
* @return
|
||
*/
|
||
fun compareList(listNew: List<String?>?, listOld: List<String?>?): Boolean {
|
||
return if (listOld == null && listNew == null) {
|
||
false
|
||
} else if (listOld != null && listNew != null) {
|
||
if (listNew.size != listOld.size) {
|
||
true
|
||
} else !(listOld.containsAll(listNew) && listNew.containsAll(listOld))
|
||
} else {
|
||
true
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 比较两个String 是否改变过
|
||
*
|
||
* @param newStr
|
||
* @param oldStr
|
||
* @return
|
||
*/
|
||
fun compareString(newStr: String?, oldStr: String?): Boolean {
|
||
return if (newStr == null && oldStr == null) {
|
||
false
|
||
} else if (newStr != null && oldStr != null) {
|
||
newStr != oldStr
|
||
} else {
|
||
true
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 比较签名 是否改变过
|
||
*
|
||
* @param newStr
|
||
* @param oldStr
|
||
* @return
|
||
*/
|
||
fun compareSign(newStr: String, oldStr: String): Boolean {
|
||
return if (TextUtils.isEmpty(oldStr)) { //当原始值没有的时候 无需验证 因为上报时需验证是否已签过字 而且当原始值有的时候 依据现有业务新值不可能清空 故无需再判断其他情况
|
||
true
|
||
} else newStr != oldStr
|
||
}
|
||
|
||
/**
|
||
* 随机生成一个UUID
|
||
*/
|
||
fun createUUID(): String {
|
||
return UUID.randomUUID().toString()
|
||
}
|
||
|
||
fun createUUIDFromLong(): String {
|
||
return UUID(ThreadLocalRandom.current().nextLong(), ThreadLocalRandom.current().nextLong()).toString()
|
||
}
|
||
|
||
/**
|
||
* MD5加密
|
||
*/
|
||
fun getMD5String(data: String): String? {
|
||
try {
|
||
val md = MessageDigest.getInstance("MD5")
|
||
md.update(data.toByteArray())
|
||
val result = md.digest()
|
||
val stringBuffer = StringBuffer()
|
||
for (i in result.indices) {
|
||
val hex = Integer.toHexString(0xff and result[i].toInt())
|
||
if (hex.length == 1) stringBuffer.append('0')
|
||
stringBuffer.append(hex)
|
||
}
|
||
return stringBuffer.toString()
|
||
} catch (e: NoSuchAlgorithmException) {
|
||
e.printStackTrace()
|
||
}
|
||
return null
|
||
}
|
||
|
||
/**
|
||
* 对数组进行MD5加密
|
||
*
|
||
* @param bytes
|
||
* @return
|
||
*/
|
||
fun getMD5Byte(bytes: ByteArray?): String? {
|
||
try {
|
||
val md = MessageDigest.getInstance("MD5")
|
||
md.update(bytes)
|
||
val result = md.digest()
|
||
val stringBuffer = StringBuffer()
|
||
for (i in result.indices) {
|
||
val hex = Integer.toHexString(0xff and result[i].toInt())
|
||
if (hex.length == 1) stringBuffer.append('0')
|
||
stringBuffer.append(hex)
|
||
}
|
||
return stringBuffer.toString()
|
||
} catch (e: NoSuchAlgorithmException) {
|
||
e.printStackTrace()
|
||
}
|
||
return null
|
||
}
|
||
|
||
//两个数组进行相加
|
||
fun addByte(array1: ByteArray, array2: ByteArray): ByteArray {
|
||
val combined = ByteArray(array1.size + array2.size)
|
||
System.arraycopy(array1, 0, combined, 0, array1.size)
|
||
System.arraycopy(array2, 0, combined, array1.size, array2.size)
|
||
return combined
|
||
}
|
||
|
||
//格式化时间yyyy-mm-dd
|
||
fun getSimpleYYYYMMDD(str: String): String {
|
||
if (TextUtils.isEmpty(str)) return ""
|
||
|
||
val simpleDateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.CHINA)
|
||
val date = simpleDateFormat.parse(str)
|
||
return simpleDateFormat.format(date!!)
|
||
|
||
}
|
||
|
||
|
||
/**
|
||
* 将字符串中的unicode字符转换为中文字符
|
||
*/
|
||
fun convertUnicodeToCh(str: String): String {
|
||
var newStr = str
|
||
val pattern: Pattern = Pattern.compile("(\\\\u(\\w{4}))")
|
||
val matcher: Matcher = pattern.matcher(newStr)
|
||
|
||
// 迭代,将str中的所有unicode转换为正常字符
|
||
while (matcher.find()) {
|
||
val unicodeFull = matcher.group(1) // 匹配出的每个字的unicode,比如\u83b7
|
||
val unicodeNum = matcher.group(2) // 匹配出每个字的数字,比如\u83b7,会匹配出u83b7
|
||
|
||
// 将匹配出的数字按照16进制转换为10进制,转换为char类型,就是对应的正常字符了
|
||
@Suppress("RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS")
|
||
val singleChar = unicodeNum.toInt(16).toChar()
|
||
|
||
// 替换原始字符串中的unicode码
|
||
@Suppress("NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS")
|
||
newStr = newStr.replace(unicodeFull, singleChar.toString() + "")
|
||
}
|
||
return newStr
|
||
}
|
||
|
||
// 解析函数
|
||
fun parseAlipayResult(rawResult: String): Map<String, String> {
|
||
val resultMap = mutableMapOf<String, String>()
|
||
val pairs = rawResult.split("&")
|
||
|
||
for (pair in pairs) {
|
||
val keyValue = pair.split("=")
|
||
if (keyValue.size == 2) {
|
||
val key = URLDecoder.decode(keyValue[0], "UTF-8")
|
||
val value = URLDecoder.decode(keyValue[1], "UTF-8")
|
||
resultMap[key] = value
|
||
}
|
||
}
|
||
return resultMap
|
||
}
|
||
}
|
||
|