AGCRN

텍스트와 인코딩

글자 수는 맞는데 바이트 제한을 넘는 이유

한글, 이모지, 결합 악센트 예시로 유니코드 코드 포인트, 눈에 보이는 글자, JavaScript 문자열 길이, UTF-8 바이트 수를 비교합니다.

angelcrown · 수정일 · 한국어

값을 바꿔 직접 확인하세요

아래 예제는 이 페이지 안에서 계산됩니다. 본문의 계산 과정과 비교해 보세요.

코드 포인트
5
UTF-16 단위
6
자소 클러스터
5
UTF-8 바이트
10
코드 포인트별 바이트 확인 (앞 24개)
  • A · U+0041 · 1 B
  • SPACE · U+0020 · 1 B
  • 가 · U+AC00 · 3 B
  • LF · U+000A · 1 B
  • 😀 · U+1F600 · 4 B

공백과 줄바꿈도 계산합니다. 자소 클러스터는 눈에 보이는 문자에 가까운 단위이며, 브라우저의 Unicode 지원 버전에 따라 일부 최신 이모지 결과가 달라질 수 있습니다. 입력은 저장하거나 전송하지 않습니다.

어떤 제한을 맞춰야 하는지부터 확인하세요

100글자를 허용하는 입력란과 100바이트를 허용하는 API 필드는 같은 문자열을 다르게 처리할 수 있습니다. ‘글자’라는 표현만으로는 어떻게 세는지 알 수 없습니다. 눈에 보이는 기호 하나가 여러 유니코드 코드 포인트로 이루어질 수 있고, 각 코드 포인트도 UTF-8로 인코딩하면 여러 바이트가 필요할 수 있습니다.

HaloBench의 ‘글자 수’는 Array.from(text).length로 유니코드 코드 포인트를 셉니다. ‘UTF-8 바이트’는 new TextEncoder().encode(text).length로 측정합니다. 사람이 보통 하나의 글자로 인식하는 묶음인 자소 군집(grapheme cluster)을 세는 것은 아닙니다. JavaScript의 text.length는 UTF-16 코드 단위를 세므로 또 다른 값입니다. 이 네 가지 결과를 같은 것으로 취급하지 말고, 입력할 서비스가 명시한 기준에 맞추세요.

같은 입력을 네 가지 기준으로 세어 보면

아래 표의 각 행은 앞뒤 공백이나 줄바꿈이 없는 입력 하나를 뜻합니다. 악센트가 붙은 e 두 개는 비슷하게 보이지만, 두 번째는 알파벳 뒤에 결합 악센트가 이어진 형태입니다. 가족 이모지는 네 사람을 세 개의 폭 없는 연결 문자로 이어 붙입니다. 글꼴이 이를 한 기호로 표시하더라도 내부 텍스트는 일곱 개의 코드 포인트로 구성됩니다.

입력HaloBench 글자 수UTF-16 코드 단위자소 군집UTF-8 바이트
A (U+0041)1111
가 (U+AC00)1113
😀 (U+1F600)1214
é (U+00E9)1112
é (U+0065 + U+0301)2213
👨‍👩‍👧‍👦 (연결된 문자 묶음)711125

공백과 줄바꿈은 여러 결과에 영향을 줍니다

짧은 조합 예시로 A, 일반 공백 한 칸, 가, 줄바꿈 한 번, 😀를 입력해 보세요. HaloBench에는 글자 수 5, 공백 제외 3, 단어 수 3, 줄 수 2, UTF-8 바이트 10이 표시됩니다. 바이트 계산은 1 + 1 + 3 + 1 + 4입니다. 이 예시의 줄바꿈은 일부 텍스트 파일에서 쓰는 두 문자짜리 CRLF가 아니라 LF 한 문자입니다.

‘공백 제외’는 탭과 줄바꿈을 포함해 JavaScript의 공백 문자에 해당하는 부분을 제거합니다. 스페이스 키로 입력한 보통 공백만 빼는 계산은 아닙니다. ‘단어 수’는 앞뒤 공백을 제거한 텍스트를 공백 문자로 나눕니다. 따라서 공백 없는 中文测试는 여기서 네 단어가 아니라 한 단어입니다. ‘줄 수’는 입력한 줄바꿈을 세며, 좁은 입력 상자 때문에 화면에서 자동으로 접힌 줄은 세지 않습니다. 맨 끝에 줄바꿈을 붙이면 빈 줄 하나가 추가됩니다.

A 가
😀

입력 폼이나 API 제한에 맞추는 순서

실제로 제출할 텍스트의 정확한 사본을 보관하세요. 계산한 뒤 문장부호를 바꾸거나 이모지를 추가하거나 마지막 줄바꿈까지 복사하면 결과가 달라질 수 있습니다. 계산기는 거절 원인을 찾는 데 도움이 되지만, 다른 서비스의 서버가 공개하지 않은 규칙까지 알아낼 수는 없습니다.

  1. 대상 서비스의 제한이 바이트, 코드 포인트, 눈에 보이는 글자, 자체 가중치 중 무엇인지 확인합니다. 단순히 ‘글자’라고만 쓰여 있다면 짧은 이모지 예시를 대상 서비스의 계산기에 넣어 비교합니다.
  2. 제출할 텍스트를 그대로 HaloBench 글자 수·단어 수 계산기에 붙여 넣습니다. UTF-8 바이트 제한이면 ‘UTF-8 바이트’를, 코드 포인트 제한이면 ‘글자 수’를 확인합니다.
  3. 결과가 예상보다 크면 공백, 탭, 마지막 줄바꿈을 확인합니다. 제출에 성공하려고 의미 있는 띄어쓰기까지 무조건 없애지는 마세요.
  4. 똑같이 보이는 글자의 결과가 다르면 유니코드 구성을 비교합니다. 미리 조합된 é는 UTF-8 2바이트이고, e 뒤에 결합 악센트를 붙이면 3바이트입니다.
  5. 대상 서비스에 제출한 뒤 그곳의 결과를 확인합니다. JSON 이스케이프, 다른 인코딩, 정규화, 서버 측 변환 때문에 실제 전송 데이터가 여기서 센 일반 텍스트와 달라질 수 있습니다.

JavaScript에서 같은 결과를 재현하기

아래 예시는 편집기가 결합 악센트를 미리 조합된 글자로 조용히 바꾸지 못하도록 이스케이프 표기를 사용합니다. 자소 군집 비교에는 Intl.Segmenter를 사용합니다. 자소 군집 수는 차이를 설명하기 위한 값이며, 현재 HaloBench 화면이 제공하는 지표는 아닙니다.

const text = "e\u0301";
const segmenter = new Intl.Segmenter("en", {
  granularity: "grapheme",
});

console.table({
  codePoints: Array.from(text).length, // 2
  utf16Units: text.length,            // 2
  graphemes: Array.from(segmenter.segment(text)).length, // 1
  utf8Bytes: new TextEncoder().encode(text).length,       // 3
});

이 계산으로 알 수 없는 것

UTF-8 값은 현재 입력란의 텍스트를 인코딩했을 때의 크기입니다. 내려받은 문서 파일 전체의 용량, UTF-16 파일 크기, 헤더와 JSON 문법까지 포함한 HTTP 요청 크기가 아닙니다. 브라우저 입력란은 줄바꿈 형식을 통일할 수 있으므로, 디스크에 저장된 파일의 바이트 제한을 정확히 맞춰야 한다면 파일 자체를 검사해야 합니다.

HaloBench는 계산 전에 텍스트를 정규화하지 않습니다. 유니코드 정규화는 눈에 보이는 단어를 바꾸지 않고도 문자 구성을 바꿀 수 있지만, 이것 역시 데이터를 변환하는 작업입니다. 받는 시스템이 그런 동작을 명시하지 않았다면 비밀번호, 식별자, 서명된 메시지처럼 정확히 일치해야 하는 값을 임의로 정규화하지 마세요.

실제 도구에서 사용하기

기술 참고 자료

잘못된 결과나 이해하기 어려운 설명이 있다면 입력 예제, 예상 결과, 브라우저 버전과 함께 알려주세요. 개인정보·비공개 파일·인증 정보는 보내지 마세요. 수정 제안 (문의 페이지는 영어)