Tempo Di Valse

[Kotlin] 문자열 배열 한글, 영문, 숫자로 정렬 시키기 본문

개발/Android

[Kotlin] 문자열 배열 한글, 영문, 숫자로 정렬 시키기

TempoDiValse 2022. 1. 26. 18:17

우선 출처는, 

 

한글-영어-특수문자 순 정렬하는 java compare 메서드 만들기

카톡을 보게 되면, 한글 -> 영문 -> 특수문자 순으로 정렬을 합니다. 지난 번 프로젝트 하면서 동일한 요구사항이 있었는데, 생각보다 머리아프더라고요. 그냥 문자열순으로 정렬하면 그 순서가

www.reimaginer.me

저 분께서 만들어주신 아주 좋은 소스를 토대로 코틀린으로 변환하여 만들어 보았다.

 

여기서 Java 소스에서는 하나 들어가지 않는 부분이 있었는데, 그것은 자모음 합체된 단어는 정렬이 되지만 자음과 모음 따로인 단어에 대해서는 정렬이 들어가지 않았다. 그래서 그 부분만 아주 간단하게 추가하여 각색해 보았다

 

object OrderKoreanFirst {
        private const val LEFT = -1
        private const val RIGHT = 1
        
        fun compare(left: String, right: String) : Int {
            val _left = left.uppercase().filterNot(Char::isWhitespace)
            val _right = right.uppercase().filterNot(Char::isWhitespace)

            val (llen, rlen) = _left.length to _right.length
            val mlen = llen.coerceAtMost(rlen)

            for(i in 0 until mlen){
                val (lc, rc) = _left[i] to _right[i]

                if(lc != rc) {
                    return if(conditionKoreanAndEnglish(lc, rc)
                        || conditionKoreanAndNumber(lc, rc)
                        || conditionEnglishAndNumber(lc, rc)
                        || conditionKoreanAndSpecial(lc, rc))
                                -(lc - rc)
                    else if(conditionEnglishAndSpecial(lc, rc) || conditionNumberAndSpecial(lc, rc)){
                        if(isEnglish(lc) || isNumber(lc)) LEFT else RIGHT
                    } else { lc - rc }
                }
            }

            return llen - rlen
        }

        // 어차피 대분자로 치환한 후 비교 하기 때문에 대문자만 비교하는 것으로 변경
        private fun isEnglish(ch: Char) : Boolean = ch in 'A'..'Z'
        // 'ㄱ'~'ㅣ' 까지 연속선상의 유니코드이기 때문에 한글로 인식하도록 추가
        private fun isKorean(ch: Char) : Boolean = ch in 'ㄱ'..'ㅣ' || ch in '가'..'힣'
        private fun isNumber(ch: Char) : Boolean = ch in '0'..'9'
        private fun isSpecial(ch : Char) : Boolean = ch in '!'..'/' || ch in ':'..'@' || ch in '['..'`' || ch in '{'.. '~'

        private fun conditionKoreanAndEnglish(c1: Char, c2: Char) = isKorean(c1) && isEnglish(c2) || isEnglish(c1) && isKorean(c2)
        private fun conditionKoreanAndNumber(c1: Char, c2: Char) = isKorean(c1) && isNumber(c2) || isNumber(c1) && isKorean(c2)
        private fun conditionKoreanAndSpecial(c1: Char, c2: Char) = isKorean(c1) && isSpecial(c2) || isSpecial(c1) && isKorean(c2)
        private fun conditionEnglishAndNumber(c1: Char, c2: Char) = isEnglish(c1) && isNumber(c2) || isNumber(c1) && isEnglish(c2)
        private fun conditionEnglishAndSpecial(c1: Char, c2: Char) = isEnglish(c1) && isSpecial(c2) || isSpecial(c1) && isEnglish(c2)
        private fun conditionNumberAndSpecial(c1: Char, c2: Char) = isNumber(c1) && isSpecial(c2) || isSpecial(c1) && isNumber(c2)
    }
 

사용은 compare 함수를 Comparator 에 넣어주면 될 것이다.

arrayOf("a", "b", "c", "ㄱ", "ㄴ", "ㄷ", "1", "2", "3")
        .sortedWith(Comparator(OrderKoreanFirst::compare))
 

이런식으로?

 

반응형
Comments