← 모두의 툴

숫자도 기술적으로는 이모지다? — Intl.Segmenter와 이모지 오탐 문제

가이드 · 2026.08.21 최종 확인

"이모지만 지워주세요"라는 요청은 얼핏 단순해 보이지만, 유니코드 표준 안에는 숫자 0~9와 #, *가 공식적으로 "Emoji" 속성을 가진 문자로 분류되어 있다는 함정이 숨어 있습니다. 이 사실을 모르고 만든 이모지 제거 도구는 본문에 있는 평범한 숫자와 기호까지 지워버리는 오탐을 냅니다. 왜 이런 분류가 생겼고, 어떻게 처리해야 오탐을 막을 수 있는지 원리를 살펴봅니다.

1. 왜 숫자가 "이모지"로 분류되는가: 키캡 이모지의 재료이기 때문

0️⃣부터 9️⃣, #️⃣, *️⃣ 같은 "키캡(keycap)" 이모지를 본 적이 있을 겁니다. 이 이모지들은 실제로는 단일 문자가 아니라, 베이스 문자(숫자 0~9, #, *) 뒤에 변형 선택자(Variation Selector, U+FE0F)와 결합 키캡 문자(U+20E3, Combining Enclosing Keycap)가 붙어서 만들어지는 합성 시퀀스입니다. 유니코드 표준은 이 시퀀스를 만들 수 있는 "재료"인 베이스 문자 자체에도 Emoji 속성을 부여해두었습니다. 그래서 순수한 숫자 "5"라는 글자 하나만 놓고 봐도, 유니코드 데이터베이스상으로는 Emoji=Yes로 표시됩니다.

속성 비교: 문자 "5"(U+0035)는 Emoji_Presentation 속성은 없지만 Emoji 속성 자체는 Yes입니다. 반면 "5️⃣"는 U+0035 + U+FE0F + U+20E3 세 코드포인트가 결합된 시퀀스입니다. `/\p{Emoji}/u` 같은 정규식은 세 코드포인트 결합 여부와 무관하게 베이스 문자 "5" 하나만 봐도 매치되므로, 순진하게 이 정규식만 쓰면 본문의 평범한 "5"도 이모지로 오인해 지워버립니다.

2. 그래서 순진한 필터링이 위험한 이유

많은 이모지 제거 로직이 `/\p{Emoji}/u` 정규식 하나로 텍스트를 훑고 매치되는 문자를 지웁니다. 텍스트가 이모지 하나 없는 순수한 한글·영문 문장이라도, 그 안에 "2024년", "3번", "#1" 같은 숫자·기호가 포함되어 있다면 이 문자들까지 통째로 사라질 위험이 있습니다. 가격, 전화번호, 순위, 해시태그처럼 숫자와 #이 자주 쓰이는 텍스트에서는 이 오탐이 결과물을 조용히 망가뜨립니다 — 에러 없이 그냥 글자가 사라지기 때문에 발견하기도 어렵습니다.

3. 올바른 처리: 결합 문자가 실제로 붙어 있을 때만 제거

진짜 키캡 이모지 시퀀스로 취급해야 하는 경우는 베이스 문자 뒤에 변형 선택자(U+FE0F)나 결합 키캡(U+20E3)이 실제로 이어질 때뿐입니다. 반대로 베이스 문자 홀로 등장하면 일반 텍스트로 남겨둬야 합니다. 이모지 제거기는 Intl.Segmenter API로 텍스트를 사람이 인식하는 "글자 단위"(grapheme cluster)로 먼저 나눈 뒤, 각 단위에 대해 유니코드 Emoji 속성 정규식을 검사하면서 동시에 정규식 `/^[0-9#*]$/`로 "숫자·#·* 단독 문자"만 정확히 걸러 이모지 판정에서 제외합니다. 즉 결합 문자 없이 홀로 있는 숫자·#·*는 애초에 제거 대상에서 빠지고, 실제 키캡 이모지 시퀀스(결합 문자가 붙은 것)는 하나의 grapheme으로 인식되어 통째로 제거됩니다.

입력실제 성격처리 결과
"3번째 항목"숫자 단독(결합 문자 없음)보존됨
"3️⃣번째 항목"키캡 이모지 시퀀스3️⃣ 전체가 제거됨
"#1 순위"# 단독(결합 문자 없음)보존됨

4. grapheme cluster 단위 처리가 필요한 또 다른 이유

이 오탐 방지는 텍스트를 코드포인트 하나씩이 아니라 grapheme cluster 단위로 봐야 하는 더 큰 이유의 일부입니다. 👨‍👩‍👧 같은 가족 이모지도 실제로는 남성·여성·여자아이 이모지 3개가 ZWJ(Zero Width Joiner)로 결합된 복합 문자열이라, 코드포인트 단위로 처리하면 반쪽만 지워지고 깨진 조각이 남습니다. 피부색 변형(👍🏽)이나 국기 이모지(🇰🇷)도 마찬가지로 여러 코드포인트가 하나의 grapheme으로 묶인 경우입니다. Intl.Segmenter는 이 모든 경우를 사람이 실제로 보는 단위 그대로 하나로 묶어서 처리하므로, 숫자 오탐 방지와 복합 이모지 완전 제거를 동시에 해결하는 기반이 됩니다.

5. 비슷한 문제를 겪는 다른 텍스트 처리 작업

이모지·특수 문자 처리에서 코드포인트와 grapheme의 차이를 무시하면 생기는 문제는 글자 수 세기, 문자열 자르기(truncate), 정규화 등 다른 텍스트 도구에서도 똑같이 나타납니다. 문자 수를 정확히 세고 싶다면 텍스트 통계 도구로, 이모지 개수만 별도로 확인하고 싶다면 이모지 카운터로 검증해볼 수 있습니다. 유니코드 코드포인트 레벨에서 무슨 일이 일어나는지 직접 뜯어보고 싶다면 유니코드 인스펙터가 유용합니다.

자주 묻는 질문

Q. 숫자가 이모지 속성을 가진다는 게 실제로 문제가 되는 사례가 있나요?

네. `/\p{Emoji}/u` 정규식만으로 텍스트를 필터링하는 스크립트를 그대로 쓰면, 가격("1000원"), 전화번호, 순위 표기("#1") 등에서 숫자와 #이 조용히 사라지는 사고가 실제로 발생합니다.

Q. ★, ✓ 같은 일반 기호도 같은 문제가 있나요?

아니요. ★나 ✓ 같은 일반 기호는 애초에 유니코드 Emoji 속성을 가지고 있지 않아 이 정규식에 걸리지 않습니다. 오탐 문제는 숫자 0~9, #, * 등 키캡 이모지의 재료가 되는 특정 문자에 한정됩니다.

Q. Intl.Segmenter를 안 쓰고도 이 문제를 해결할 수 있나요?

숫자 단독 오탐만 막는 것은 정규식 예외 처리로도 가능하지만, ZWJ 복합 이모지나 피부색·국기 이모지까지 안전하게 통째로 처리하려면 grapheme cluster 단위 분해가 사실상 필수입니다.

Q. 키캡 이모지 자체를 지우고 싶으면 어떻게 하나요?

변형 선택자나 결합 키캡 문자가 실제로 붙어 있는 시퀀스는 정상적으로 이모지로 판정되어 제거 대상에 포함됩니다. 단독 숫자·#·*만 예외 처리되는 것이지 진짜 키캡 이모지 시퀀스는 그대로 제거됩니다.