Google 태그 관리자 아이콘

새로운 로직접근

.findout(java와 mysql에서 emoji 길이 통일시키기)

silvergoni 2020. 12. 22. 23:12
반응형

고민

  • 서버(spring, java)와 mysql에서 emoji길이 인식의 차이가 있다.
  • 같은 이모지인데 왜 길이 값을 다르게 인식하는지 이해가 안되었다.
  • 또한 글자 길이 제한로직을 처리하기위해서는 이들의 일관된 기준이 필요하였다.

결론

  • db의 collataion을 utf8mb4임을 확인하고 서버(java)에서 String을 아래처럼 분해하여 같은 글자길이로 인식하도록 설정해서 해결하였다.

접근방법

mysql 확인

  1. mysql에서는 emoji가 제대로 잘 보였고 어떻게 그런지 확인해보았다.
  • 흔히 글자수를 제한한 필드를 선언할때 varchar(20)과 같이 선언하고 있는데 여기서 varchar의 20이 어떤 collataion으로 선언되어있는지가 중요하다.

    • 다음 명령어로 확인이 가능하였다.

      SHOW VARIABLES LIKE 'character_set_database';
  • 나같은 경우는 character_set_database: utf8mb4 로 나왔다.

    • 최대 4byte를 사용하고 BMP나 supplementary characters를 지원한다고 써있습니다.
  • 결론적으로는 varchar(20)이란 4byte로 한글자를 인식했을때의 글자길이를 20개까지 받을수 있는것이다.

  1. 해당 문자가 길이가 어떤지 알기 위해 mysql function을 이용했다.
  • LENGTH()는 위에 설명된것처럼 byte수의 합이고 CHAR_LENGTH()는 한글자를 collation기준에 따라 인식한 글자수이다.

    ex) LENGTH(👩‍🚀) == 11, CHAR_LENGTH(👩‍🚀) == 3
    //  11/4byte == 2.xxx올림해서 3
    ex) LENGTH(👩‍🚀한글) == 17(11byte+3byte+3byte), CHAR_LENGTH(👩‍🚀한글) == 5
    // 11byte에서 3글자로 인식하고 한글은 3byte여서 나누기 4를 하면 1글자씩으로 인식해서 전체 길이는 5가 된다.
    ex) LENGTH(👩‍🚀한글g) == 18(11byte+3byte+3byte+1byte), CHAR_LENGTH(👩‍🚀한글g) == 6
    // 11byte 3글자, 3byte 2글자, 1byte(영어) 1글자로 해서 6이 된다.
  • 결론적으로 db에서는 4byte기준으로 글자를 인식하고 위와같은 길이로 인식하고 있었기에 db를 바꿀순 없고 서버로직을 db에 맞추어 일관되게 맞춰보기로 했습니다.

서버에서 mysql utf8mb4와 같은 효과내기

  1. java에서 mysql utf8mb4을 대응할 수 있는 코드가 있었으면 좋으려만 잘 찾지 못하였다.
  • 꿩대신 닭이라고 결국 원리는 한 글자를 몇바이트로 인식할것이냐는 관점에서 출발했다.

  • utf8mb4에서는 한글자를 4byte로 보고 있기에 utf-32로 해보면 어떨까?

    일단 32비트(4byte)단위의 글자로 변경함:  "".getBytes("UTF-32")
  • StandardCharset에는 UTF-32는 없다. 텍스트로 대체하기로 했다.

  1. 1번을 거치면 UTF-32인코딩으로 byte개수를 리턴하기에 4byte를 1글자로 보기위해 나누기 4를 한다.
  • 전체적으로 다 확인해보진 못했습니다만 아래와 같은 결과를 얻을 수 있다.

    ex) "👩‍🚀".getBytes("UTF-32").length = 12
    ex) "👩‍🚀".getBytes("UTF-32").length/4 = 3
    //4byte를 한글자로 보니 4로 나눔
    ex) "👩‍🚀한글".getBytes("UTF-32").length/4 = 5
    //4byte를 한글자로 보니 4로 나눔

참고