在业务开发过程,不免遇到一些比较复杂的排序场景:按学生姓名拼音首字母排序,按英文字顺序排序,如果是中英混合还期望先按英文排序、再按中文排序…本文将针对这些场景提供对应的解决方式。
这里我们借助pinyin4j工具包
<!-- https://mvnrepository.com/artifact/com.belerweb/pinyin4j -->
<dependency>
<groupId>com.belerweb</groupId>
<artifactId>pinyin4j</artifactId>
</dependency>
fun main() {
val result = listOf("赫尔", "里昂", "肯尼").sortedWith(
Comparator { o1, o2 ->
SortUtil.compareByPinyinAndDigital(o1, o2)
}
)
result.forEach {
println(it) //赫尔、肯尼、里昂
}
}
fun compareByPinyin(compareStr1: String, compareStr2: String): Int {
val str1 = getPinyinInitials(compareStr1).toLowerCase()
val str2 = getPinyinInitials(compareStr2).toLowerCase()
return str1.compareTo(str2)
}
/**
* 获取拼音
*
* @param text 文本
* @return {@link String}
*/
private fun getPinyinInitials(text: String): String {
val sb = StringBuilder()
for (c in text) {
val pinyinArray = PinyinHelper.toHanyuPinyinStringArray(c)
if (pinyinArray != null && pinyinArray.isNotEmpty()) {
sb.append(pinyinArray.first())
} else {
sb.append(c)
}
}
return sb.toString()
}
fun main() {
val result = listOf("12赫尔", "av喝水", "荷花", "黑王").sortedWith(
Comparator { o1, o2 ->
SortUtil.sortByCustomRegular(o1, o2)
}
)
result.forEach {
println(it) // 荷花 黑王 av喝水 12赫尔
}
}
/**
* 定制的排序规则
* 等第制的排序规则
* 中文>英文>数字>null
*
* @param compareStr1
* @param compareStr2
* @return
*/
companion object {
fun sortByCustomRegular(compareStr1: String?, compareStr2: String?): Int {
if (StringUtils.isBlank(compareStr1)) {
return 1
}
if (StringUtils.isBlank(compareStr2)) {
return -1
}
val c = charArrayOf(compareStr1!!.toLowerCase()[0], compareStr2!!.toLowerCase()[0])//首字母
val str = arrayOf(compareStr1.substring(0, 1), compareStr2.substring(0, 1))
val type = intArrayOf(1, 1)
//判断两个字符串是什么类型
for (i in 0..1) {
when {
//中文字符
str[i].matches("[\\u4e00-\\u9fbb]+".toRegex()) -> type[i] = 1
c[i] in 'a'..'z' -> type[i] = 2
c[i] in '1'..'9' -> type[i] = 3
else -> type[i] = 4
}
}
//比较两个中文
if (type[0] == 2 && type[1] == 2)
return Collator.getInstance(Locale.CHINA).compare(compareStr1, compareStr2)
//比较两个英文,比较中文和英文
return if (type[0] == type[1]) compareStr1.compareTo(compareStr2) else type[0] - type[1]
}