JavaScript / 문자열 length와 글자 수 차이, 이모지 길이 계산
String.length는 문자열의 UTF-16 코드 단위 개수를 반환하는 속성입니다. 영문자나 보통의 한글 음절은 각각 한 단위이지만 일부 이모지와 결합 문자는 화면에 보이는 글자 수와 다를 수 있습니다. 입력 제한을 만들 때는 어떤 “길이”를 제한할지 먼저 정하세요.
length의 기본 사용법
text.length처럼 괄호 없이 읽습니다. 빈 문자열의 길이는 0이고 공백도 문자열을 이루는 단위에 포함됩니다. 단순한 ASCII 문자와 보통의 한글 음절에서는 문자 수와 결과가 같아 보일 수 있습니다.
console.log('abcd'.length); // 4
console.log('한글'.length); // 2
console.log(''.length); // 0
console.log('a b'.length); // 3: 공백 포함
문자열은 배열과 달리 length를 대입해 내용을 잘라내는 방식으로 바꿀 수 없습니다. 길이를 바꾸려면 slice() 등으로 새 문자열을 만들어야 합니다. MDN의 String.length 문서에서 이 속성이 UTF-16 단위라는 정의를 확인할 수 있습니다.
UTF-16 단위와 코드 포인트 수가 다른 경우
일부 유니코드 문자는 UTF-16 코드 단위 두 개로 표현됩니다. 이때 length는 2이지만, 문자열 반복자가 읽는 코드 포인트는 1개입니다. Array.from(text).length는 코드 포인트 개수를 세는 데 사용할 수 있으나, 이것도 사용자 눈에 보이는 글자 묶음 수와 항상 같지는 않습니다.
const face = String.fromCodePoint(0x1F642);
console.log(face.length); // 2: UTF-16 코드 단위
console.log(Array.from(face).length); // 1: 코드 포인트
예를 들어 결합 악센트는 앞 글자와 함께 한 글자처럼 보일 수 있어도 코드 포인트가 둘입니다. 글자를 잘라 보여 주는 기능을 만들 때 UTF-16 길이로 자르면 일부 이모지의 한쪽 단위만 남을 수 있습니다.
화면에 보이는 글자 묶음 세기
사용자에게 보이는 문자 묶음, 즉 자소 묶음(grapheme cluster)을 세려면 Intl.Segmenter의 granularity: "grapheme"을 사용할 수 있습니다. 대상 브라우저의 지원 범위를 확인하고, 지원하지 않으면 이 방식이 필요할 때 대체 구현을 준비하세요.
const sample = 'A' + String.fromCodePoint(0x1F642) +
'e' + String.fromCharCode(0x0301);
const segmenter = new Intl.Segmenter('ko', { granularity: 'grapheme' });
console.log(sample.length); // 5
console.log(Array.from(sample).length); // 4
console.log(Array.from(segmenter.segment(sample)).length); // 3
여기서 A, 얼굴 기호, 결합 악센트가 붙은 e가 각각 화면에 보이는 묶음 하나입니다. 입력 폼의 제한이 파일 형식이나 API의 UTF-16 길이를 뜻하는지, 사람이 보게 되는 글자 수를 뜻하는지에 따라 검사 기준이 달라집니다. MDN의 Intl.Segmenter 문서에 문자 분할 옵션이 정리되어 있습니다.
전체 예제: 입력하면서 세 기준 비교하기
아래 코드를 UTF-8로 string-length.html에 저장해 브라우저에서 엽니다. 입력할 때마다 UTF-16 단위 수, 코드 포인트 수, 표시 문자 묶음 수를 함께 보여 줍니다. Intl.Segmenter가 없는 환경에는 표시 문자 묶음의 지원 상태를 알립니다.
<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>문자열 길이 기준 비교</title>
</head>
<body>
<label for="text">문자열을 입력하세요</label>
<textarea id="text" rows="3" cols="40">한글</textarea>
<pre id="output" aria-live="polite"></pre>
<script>
const input = document.querySelector('#text');
const output = document.querySelector('#output');
const segmenter = typeof Intl.Segmenter === 'function'
? new Intl.Segmenter('ko', { granularity: 'grapheme' }) : null;
function render() {
const value = input.value;
const points = Array.from(value).length;
const graphemes = segmenter
? Array.from(segmenter.segment(value)).length : '이 환경에서 미지원';
output.textContent = `UTF-16 단위 length: ${value.length}\n` +
`코드 포인트 수: ${points}\n` +
`표시 문자 묶음 수: ${graphemes}`;
}
input.addEventListener('input', render);
render();
</script>
</body>
</html>
처음 입력된 한글은 세 결과가 모두 2입니다. 일부 이모지를 한 개 입력하면 UTF-16 길이는 2, 코드 포인트와 표시 문자 묶음 수는 각각 1인 결과를 볼 수 있습니다. 결합 문자를 입력하면 코드 포인트와 표시 묶음이 다를 수 있습니다. 실제 글자 수 제한을 적용할 때는 선택한 기준을 안내 문구와 서버 검증에도 일치시키세요.




