【Kotlin】中英数字混合等多种情况下的排序方式

发布时间:2024年01月08日

背景

在业务开发过程,不免遇到一些比较复杂的排序场景:按学生姓名拼音首字母排序,按英文字顺序排序,如果是中英混合还期望先按英文排序、再按中文排序…本文将针对这些场景提供对应的解决方式。

实践

  1. 按拼音首字母排序、或者混合着数字和英文

这里我们借助pinyin4j工具包

<!-- https://mvnrepository.com/artifact/com.belerweb/pinyin4j -->
<dependency>
    <groupId>com.belerweb</groupId>
    <artifactId>pinyin4j</artifactId>
</dependency>
  • 如下我们提供的compareByPinyin方法,会对两个字符串进行比较并返回一个int类型数值,大于0时,表示compareStr1compareStr2前面。
  • 当有英文和数字时,下面方法默认会**按数字->英文->中文顺序排序,**如"赫尔", “123C里昂”, “C肯尼”,排序后是"123C里昂"、“C肯尼”、“赫尔”。
  • 注意!这里借助pinyin4j获取的拼音结果会带声调的,比如同音情况下,“赫尔”, “喝水”, “荷花”,结果将返回 “he4er3”,“he1shui3”,“he2hua1”,由于此时带有**数字,**造成排序结果会是 **“喝水”,“荷花”,“赫尔”,**业务使用时,还是需要结合实际情况,看看需不需要过滤数字
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()
        }


  1. 上面的排序是固定**数字->英文->中文顺序排序,**如果想按照自定义规则排序,那么我们可以考虑如下的方式
  • 这里相当于把首字符拆出来,如果都是中文,就走中文比较,如果不是,两个字符类型又都相同(都是数字或者都是字母),就走正常比较逻辑,否则**type[i]的值比较,保证中文>英文>数字>null **顺序。
  • 注意!这里的中文比较用的是Collator类,在Java里,采用的是UNICODE编码,而对于中文的UNICODE字符集,它是源于GB18030的,而GB18030又发展自GB2312,GB2312收录的中文字符个数大概6763个汉字,按照拼音排序,并且是连续的。如果是非这个字符集收录的汉字排序可能就会乱,如果对这个要求严格可能得考虑pinyin4j。
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]
        }
文章来源:https://blog.csdn.net/legendaryhaha/article/details/135466033
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。