Post

Java/ 한글 정규화문제

Java/ 한글 정규화문제

환경

  • Java 17

문제 상황

운영중인 서비스의 기능중에 채팅 시스템이 있다.

채팅 시스템을 통하여 client끼리 주고받은 내용을 Redis+RDBS에 저장하여 이를 로그형태로 저장, 향후 관리자가 엑셀파일형태로 볼 수 있게 한다.

레디스에 일반적인 대화메시지를 저장하기도하고, 클라이언트끼리 파일을 주고받을 경우 파일명을 그대로 redis및 RDBS에 저장한다.

불러올때는 문제가 없어보였으나 엑셀을 다운로드하면 한의 자음 모음이 깨져서 보였다.

일반 대화메시지는 괜찮은데, 유독 파일 전송시, 파일명만 깨져서 보였다.

해결과정

데이터를 레디스나 MySQL에서 불러올때 한글의 문제라면 일반적인 텍스트도 깨졌을거라 생각했다.

파일명의 경우에만 문제가 생긴 것에 대한 초점을 맞춰보았다.

유저가 메세지를 쓸때는 텍스트 그대로 넘기겠지만 파일명의 경우에는 중간에 전처리 과정이 있지 않을까 했다.

텍스트와 달리 파일첨부는 스토리지에서 파일을 유저가 더블클릭하면 더블클릭한 파일명을 찾고 이를 어떤 형식으로 서버에 보낸다고 생각했다. 이 과정속에서 문제가 생겼을 가능성이 있다고 생각했다.

결과적으로는 이 문제가 맞았다.

NFC? NFD

문제 현상을 이해하려면 NFC(Normalization Form Composition), NFD(Normalization Form DeComposition) 에 대한 이해가 필요하다.

운영체제별로 Unicode정규화 방식이 다른데, NFC, NFD는 그 정규화 방식 중 하나다.

Mac OS는 NFD를 사용하고 Window에서는 NFC를 사용한다고 알려져있다.

NFD는 ‘각’이라는 글자를 ‘ㄱ’+’ㅏ’+’ㄱ’로 저장하는 방식이다. NFC는 ‘각’이라는 글자를 ‘각’으로 저장한다.

NFD는 텍스트의 크기가 커진다는 문제가 있지만 세부적인 조작이 가능하다는 장점이 있다.

NFC,NFD 판단방법

다행스럽게도 Java에서는 Normalizer라는 클래스를 통해 NFC/NFD판단이 가능하다.

1
2
3
4
5
6
if(content.getFileName()!= null) {
    String data = Normalizer.normalize(content.getFileName(), Normalizer.Form.NFC);
    System.out.println("값 : "+ data);
    System.out.println(Normalizer.isNormalized(content.getFileName(), Normalizer.Form.NFC));
    System.out.println(Normalizer.isNormalized(content.getFileName(), Normalizer.Form.NFD));
}

위의 문제가 되었던 경우 실제 결과는 다음과 같다.

1
2
3
값 : 스크린샷 2023-08-10 오후 4.00.02.png
false
true

즉 받아온 데이터들이 NFC가 아닌 NFD형태로 받고 있어서 모음/자음 분리 문제가 발생했던 것이다.

해결방법

이를 해결하는 방법은 간단하다. 위의 코드에 답이 있는데, NFC형태로 값을 다시 변환해주면된다.

즉, String data = Normalizer.normalize(content.getFileName(), Normalizer.Form.NFC)이 구문을 통해 NFC형태로 값을 변환해줄 수 있으며 이를 통해 해결할 수 있다.

후기

인코딩쪽에 뭔가 문제가 있을거라고는 생각했지만 이런경우 만만치않게 답답했다.

Redis, DB와 연결되어있어서 그쪽 문제인지도 찾아봐야하나 했는데 그쪽으로 깊게 갔으면 더 못찾았을 것이다. 그 근간에는 인코딩이 있으니 이번 경험을 통하여 역시나 기본기가 중요하다는 생각을 하게 되었다.

This post is licensed under CC BY 4.0 by the author.