Posts 이모지(emoji) 삽입 실패 문제 해결
Post
Cancel

이모지(emoji) 삽입 실패 문제 해결

개요

  • DB 관련 에러를 처리하여 이를 기록한다.
  • DB에러는 Error 1366: Incorrect string value 로 입력된 string에
    특정 emoji가 포함되어 발생하는 것으로 파악되었다.
  • 여러 방법 중 문제의 emoji를 대체 텍스트로 변경하는 방법으로 해결하였다.

문제 발생 이유

  • MariaDB collation
    • MariaDB에서 table을 생성할 때 charset과 collation을 지정한다.
    • charset은 문자(기호)와 인코딩의 집합이고,
      collation은 charset안의 문자들의 비교를 위한 규칙들이다(참고).
    • 보통 한국어가 포함되는 테이블의 charset은 utf8, collation은 utf8_general_ci를 사용한다.
  • utf8_general_ci는 3byte만 허용
    • utf8은 유니코드 문자 인코딩 방식 중 하나이다.
    • utf8은 4byte까지 사용하나 전세계 언어를 표현하는데에는 3byte면 충분하다.
    • 그래서 Mysql 및 MariaDB에는 효율성을 위해 utf8_general_ci를 3byte로 설계했다.
    • 그러나 emoji 중 4byte짜리가 등장하면서
      utf8_general_ci에 저장하지 못하는 문제가 발생한 것이다.

해결방법 1: collation 변경

  • MariaDB collation을 utf8_general_ci를 utf8mb4_unicode_ci로 바꾼다.
    • utf8mb4_unicode_ci collation은 4byte utf8 인코딩도 저장할 수 있다.
    • 그러나 운영 중인 DB의 설계를 변경하는 것을 꽤나 큰 리스크이기 때문에
      우리는 4byte emoji를 필터링 하는 방법을 선택했다.
  • 유의사항

해결방법 2: 4byte emoji를 대체 텍스트로 치환

  • Golang에서 정규식(Regular expression)으로 emoji 처리하기
    • utf8 인코딩은 16진수로 표현한다. ex. U+0800
    • 정규식에서의 표현은 \u0800 와 같이 표현할 수 있는데
      Golang에서는 이 표현 대신 \x{0800}으로 표현한다(참고)
  • 4byte emoji의 16진수 값 확인
  • 4byte emoji를 대체 텍스트로 치환하는 코드
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
      package main
    
      import (
          "fmt"
          "regexp"
      )
    
      func main() {
          var emojiRx = regexp.MustCompile(`[\x{1F004}-\x{1F9E6}]|[\x{1F600}-\x{1F9D0}]`)
          var s = emojiRx.ReplaceAllString("Thats a nice joke 🥰 🥵 🥶 🥳 🥴 🥺 👨‍🦰 👩‍🦰 👨‍🦱 👩‍🦱 👨‍🦲 👩‍🦲 👨‍🦳 👩‍🦳 🎨 🎦", `[e]`)
          fmt.Println(s)
      }
    

참고

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