포스트

이모지(emoji)와 서버 통신

개요

우리는 매일 수많은 이모지와 문자들을 마주하게 돼요. 하지만 이 모든 문자가 어떻게 표현되고 저장되는지에 대한 이해는 그다지 흔하지 않죠. 이 포스팅에서는 이모지와 같은 복잡한 문자들이 어떻게 유니코드를 통해 처리되는지 알아보겠습니다.

이모지와 유니코드 스칼라의 관계

특정 이모지는 여러 개의 이미지로 조합되어 표현되는데요, 이런 이모지 중 대표적인 예시로 가족 이모지가 있어요.

가족 이모지는 총 7개의 유니코드 코드 포인트로 이루어져 있죠.

스위프트에서는 유니코드 스칼라로 그 개수를 확인해볼 수 있어요.

1
2
3
let familyEmoji = "👨‍👩‍👧‍👦"
print(familyEmoji.count) // 1
print(familyEmoji.unicodeScalars.count) // 여러 개의 코드 포인트를 반환

이 코드를 실행해보면 유니코드 스칼라는 7이 찍히는 것을 볼 수 있는데, 텍스트의 길이는 1이 나오는 것을 확인할 수 있어요.

단순히 텍스트 한 개라고 보긴 힘들죠. 이런 복잡한 구조를 올바르게 서버에 전달하기 위해서는 인코딩이 필수적이에요.

유니코드 인코딩의 중요성

서버에 텍스트를 전달할 때 인코딩은 필수에요. 인코딩 방법은 여러가지가 있는데요, 옛날의 ASCIIISO-8859 인코딩은 이모지를 지원하지 않아요. 그리고 이러한 인코딩들은 이모지 이외에도 다양한 언어의 문자를 표현하는 데 한계가 명확해요.

그래서 유니코드 컨소시엄이란 단체에서 여러 국가의 언어를 하나의 통일된 문자 집합으로 표현하기 위해 유니코드를 만들게 되었어요.

위 가족 이미지를 예로 들면 아래와 같은 유니코드 7개의 조합으로 이뤄져 있어요.

  • 👨 (U+1F468) - Man
  • (U+200D) - Zero Width Joiner (ZWJ)
  • 👩 (U+1F469) - Woman
  • (U+200D) - Zero Width Joiner (ZWJ)
  • 👧 (U+1F467) - Girl
  • (U+200D) - Zero Width Joiner (ZWJ)
  • 👦 (U+1F466) - Boy

유니코드는 문자에 고유한 번호, ‘코드 포인트’를 할당하기 위한 시스템이에요. 이런 코드 포인트를 2진수로 해석하는 방식이 인코딩이죠. 대표적인 유니코드 인코딩에는 UTF-8과 UTF-16이 있어요.

유니코드 인코딩을 사용하면 조합된 이모지도 안전하게 표현할 수 있어요.

1
2
3
4
5
let emoji = "👨‍👩‍👧‍👦"
let buf: [UInt8] = Array(emoji.utf8)

print(buf)
// [240, 159, 145, 168, 226, 128, 141, 240, 159, 145, 169, 226, 128, 141, 240, 159, 145, 167, 226, 128, 141, 240, 159, 145, 166]

가족 이모지를 UTF-8로 인코딩한 결과를 출력해 봤어요.

buf는 25개의 바이트로 이뤄져 있고 그 값을 보면 아까 확인한 7개의 유니코드 조합이라는 것을 어렵지 않게 확인할 수 있어요.

예를 들어 [226, 128, 141]가 4바이트 마다 등장하는 것을 볼 수 있는데 이게 바로 ZWJ이죠. 즉, 이모티콘 4개 _ 4바이트 + ZWJ 3개 _ 3바이트 = 총 25개의 바이트로 인코딩 된 거에요.

만약 서버에 이모지를 전달했는데 문자가 깨지는 등의 문제가 발생했다면 유니코드를 지원하는 인코딩을 사용했는지 먼저 확인해야해요. 그리고 서버측에서도 동일한 유니코드 인코딩(utf-8)을 사용하는지 확인해야해요. (데이터베이스 테이블 컬럼 등)

왜나하면 모두 유니코드를 지원하는 인코딩이라해도 서로 다른 바이트 구조를 사용하기 때문이이에요. 모두가 유니코드를 지원하는 동일한 인코딩을 사용하고 있다면 어떤 이모지나 국제문자를 보내도 문제가 없을 거에요.

UTF-8, UTF-16

대표적인 유니코드 인코딩에는 UTF-8과 UTF-16가 있다고 했는데요 둘은 어떤 차이점을 가지고 있을까요?

UTF-8

장점

  • ASCII 호환성: 기존의 ASCII 문자(0-127)는 UTF-8에서도 1바이트로 표현돼요. 이로 인해 많은 기존 시스템과 소프트웨어가 UTF-8을 쉽게 채택할 수 있었어요.
  • 변동 길이 인코딩: 1바이트에서 4바이트까지 문자에 따라 다양한 길이의 바이트를 사용해요. 이로 인해 영어나 숫자와 같은 문자는 효율적으로 저장돼요.
  • 웹 표준: UTF-8은 웹에서 가장 널리 사용되는 인코딩 방식이에요.

단점

  • 길이 변동: 문자에 따라 바이트 길이가 다르므로, 특정 위치의 문자를 알기 위해서는 문자열을 처음부터 탐색해야 할 수 있어요.
  • 메모리 사용: 아시아 언어와 같이 비ASCII 문자를 주로 사용하는 문자열의 경우, UTF-8은 UTF-16보다 더 많은 바이트를 사용할 수 있어요.

UTF-16

장점

  • 2바이트 기본 단위: 많은 유니코드 문자가 2바이트로 표현돼요. 이는 아시아 문자 등 많은 문자들에 대해 상대적으로 효율적이에요
  • 일부 시스템 통합: Windows와 Java 같은 시스템과 플랫폼에서 내부적으로 사용되므로, 이 환경에서는 자연스럽게 적합해요.

단점

  • 비ASCII 문자의 추가 비용: ASCII 문자는 UTF-8에서 1바이트로 표현되지만, UTF-16에서는 2바이트가 필요해요.
  • 서로게이트 쌍: 유니코드의 범위를 넘어서는 문자를 표현하기 위해서는 4바이트를 사용해야 해요. 이로 인해 인코딩과 디코딩이 복잡해질 수 있어요.

마무리

궁금했던 점은 이모지가 생각보다 자주 업데이트 되는 것 같던데 알아서 전부 유니코드에 등록이 되는건가? 하는 점이었어요.

찾아보니 애초에 제안을 먼저 하는거 같았어요. 새로 추가할 이모지를 유니코드 컨소시엄에 제안하고 검토 과정을 거쳐서 채택된다고 해요.

그러다 이모지가 너무 많아지면 어떻게 되지?도 궁금해졌는데요, 유니코드 표준은 다양한 평면(Plane)으로 구성되며, 현재 총 17개의 평면으로 이뤄져 있다고 해요.

각 평면은 65,536(= 2^16)개의 코드 포인트를 포함하고 있기 때문에 전체 유니코드 코드 포인트의 수는 17 × 65,536 = 1,114,112개이죠. 이 중 현재 할당되어 있는 문자는 약 14만개 정도라고 하니 새로운 유니코드를 할당할 때 자리 걱정은 할 필요는 없을 것 같아요.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.