[Android] 한글 종성에 따라 조사 구분하기
Toast 메시지를 띄울 때 단어에 따라 뒤에 붙는 조사가 달라져야 하는데
그렇지 않은 것을 보고 어색하다는 생각이 들었고 무엇보다 사용자들이 보기에는 좋지 않을 것으로 생각했다.
그래서 필자는 직접 확장함수를 구현해보기로 했다.
한글의 조사에는 "은", "는", "이", "가", "을", "를"이 있고,
앞에 오는 단어의 마지막 글자에 종성의 유무에 따라 뒤에 붙는 조사가 달라진다.
초성, 중성, 종성 테이블
실제 코드에서 한글은 유니코드로 구성되어 있고,
19개의 초성, 21개의 중성, 28개의 중성의 조합으로 한글이 만들어진다.
1개의 한글자는 초성 + 중성 + 종성의 조합으로 유니코드 값이 만들어진다.
이를 수식으로 표현하면 다음과 같다.
한글 = 0xAC00(처음 한글 시작값) + (초성 Index × 21 × 28 ) + (중성 Index × 28) + 종성 Index
종성의 유무에 따라 조사를 구분하기 위해서는 한글의 유니코드에 따라 분류해줘야 한다.
그리고 위의 종성 테이블을 보면 받침이 없는 경우는 종성 Index가 0으로 구성되어 있음을 알 수 있다.
따라서 1번에서 가져온 종성 Index가
0 이상일 경우 ⇒ 받침이 있는 경우이고
그렇지 않은 경우 ⇒ 받침이 없는 경우이다.
이 경우를 고려해서 마지막 철자 뒤에 "은", "는", "이", "가", "을", "를"을 붙여주면 된다.
한글 유니코드 조합
유니코드를 분해하면 다음과 같다.
초성 Index = ((한글 유니코드값 - 0xAC00) / 28) / 21
중성 Index = ((한글 유니코드값 - 0xAC00) / 28) % 21
종성 Index = (한글 유니코드값 - 0xAC00) % 28
이를 토대로 종성의 Index 값을 가져올 수 있고, Kotlin 코드로 구현하면 다음과 같다.
val lastSpell = word.last()
val index = (lastSpell.code - 0xAC00) % 28
찾고자하는 값의 마지막 글자를 가져온 후에 이 글자의 종성 index 값을 찾을 수 있다.
그렇게 해서 만든 최종 코드는 다음과 같다.
fun String.setPostPosition(firstPostPosition: String, secondPostPosition: String): String {
val lastSpell = this.last()
// 한글의 유니코드 범위를 벗어나는 경우는 그대로 리턴
if (lastSpell !in '\uAC00'..'\uD7A3') {
return this
}
// 종성 유무에 따라 값 선택
// firstPostPosition: "이", "을", "은" (종성 有)
// secondPostPosition: "가", "를", "는" (종성 無)
val postPosition = if ((lastSpell.code - 0xAC00) % 28 > 0) firstPostPosition else secondPostPosition
return this + postPosition
}
사용할 때는 다음과 같이 사용하면 된다.
val word1 = "편지"
val word2 = "우편"
val message1 = "${word1.setPostPosition("을", "를")} 보냈습니다."
val message2 = "${word2.setPostPosition("을", "를")} 보냈습니다."