본문 바로가기

Programing/JVM(Java, Kotlin)

을/를, 이/가, 은/는 을 알아서 붙여주면 좋겠다.

포켓몬을 보다 보면 조사가 옵션처럼 붙어서 뭔가 아마추어 처럼 보이는 느낌이 있다.

바로 한글의 특성 때문인데 이것을 구현하기 쉬울 거라고 생각했는데 나름 생각할게 더 있었다.



자바 코드

/**
* 한글코드 값은 아래 주소를 참고한다.
* http://jrgraphix.net/r/Unicode/AC00-D7AF
*
* 로직에 대한 이해는 아래 주소를 참고한다.
* http://gun0912.tistory.com/65
*
* 속기에 대한 글을 참고하면 좋다.
* http://blog.naver.com/blue8943/220227426526
*/
@Slf4j
public class StringUtils {

/** '가'의 한글코드 값(시작) */
private static final int HANGULE_SYLLABLES_CODE_OF_GA = 0xAC00;
/** '힣'의 한글코드 값(끝) */
private static final int HANGULE_SYLLABLES_CODE_OF_HIH = 0xD7A3;
/** 중성 오프셋 (종성 테이블의 원소의 개수이다) */
private static final int HANGULE_JUNGSUNG_OFFSET= 28;


private CheckoutStringUtils() {
// make utility class
}

/**
* 단어의 받침을 판단해서 조사를 붙여준다.
* @param word 대상 단어
* @param eunIEul '은, '이', '을' 등의 조사
* @param nunGaLul'는, '가', '를' 등의 조사
* @return 조사를 붙인 결과 문자열 (영어의 경우 word만 반환됨)
*/
public static String attachKoreanPostpositionalParticle(@Nonnull String word, String eunIEul, String nunGaLul) {
try {
if (hasPropConsonants(word)) {
return word + eunIEul;
}
return word + nunGaLul;
} catch (IllegalArgumentException ex) {
log.debug("Don't care about this", ex);
return word;
}
}

/**
* 끝 말의 받침이 존재하는지 여부 확인
* @param word 확인할 단어
* @return 존재하면 true, 없으면 false
*/
public static boolean hasPropConsonants(@Nonnull String word) {
char lastWord = getLastWord(word);

// 한글의 제일 처음과 끝의 범위밖일 경우는 오류
if (lastWord < HANGULE_SYLLABLES_CODE_OF_GA || lastWord > HANGULE_SYLLABLES_CODE_OF_HIH) {
throw new IllegalArgumentException("Parameter Should be Korean.");
}
return (lastWord - HANGULE_SYLLABLES_CODE_OF_GA) % HANGULE_JUNGSUNG_OFFSET > 0;
}

private static char getLastWord(String word) {
if (CoupangStringUtils.isNotEmpty(word)) {
return word.charAt(word.length() - 1);
}
throw new IllegalArgumentException("Parameter Should be not empty.");
}
}

테스트 코드 (Spock)

class StringUtilsTest extends Specification {
def "받침이 존재하는 '받침'은 hasPropConsonants는 true 반환"() {
when:
boolean hasPropConsonants = StringUtils.hasPropConsonants("받침")

then:
hasPropConsonants
}

def "받침이 존재하지 않는 '한국어'는 hasPropConsonants는 true 반환"() {
when:
boolean hasPropConsonants = StringUtils.hasPropConsonants("한국어")

then:
!hasPropConsonants
}

def "입력이 한글이 아닐 경우에는 hasPropConsonants는 IllegalArgumentException를 던진다."() {
when:
StringUtils.hasPropConsonants("English")

then:
IllegalArgumentException ex = thrown()
ex.message == 'Parameter Should be Korean.'
}

def "받침이 존재하는 '받침'은 attachKoreanPostpositionalParticle는 '받침을' 반환"() {
when:
String output = StringUtils.attachKoreanPostpositionalParticle("받침", "을", "를")

then:
output == "받침을"
}

def "받침이 존재하지 않는 '한국어'는 attachKoreanPostpositionalParticle는 '한국어를' 반환"() {
when:
String output = StringUtils.attachKoreanPostpositionalParticle("한국어", "을", "를")

then:
output == "한국어를"
}

def "입력이 한글이 아닐 경우에는 IllegalArgumentException를 던진다."() {
when:
String output = StringUtils.attachKoreanPostpositionalParticle("English", "을", "를")

then:
output == "English"
}
}


하지만 쉽지 않다는 것.

실생활에서는 한글만 쓰는게 아니라 영어나 숫자도 혼용해서 쓰므로.