자바스크립트의 문자열 표현 방식 UTF-16
- 자바스크립트 문자열은 유효하지 않은 대리쌍을 허용하는 일련의 UTF-16 코드 유닛이다.
- 위의 글을 읽었는데 어떤 의미인지 이해했다면, 더이상 아래의 글을 읽을 필요가 없다.
UTF-16 이란?
- 자바스크립트 문자열의 표현 방식이다.
- 흔히 볼 수 있는 문자열 인코딩 방식이다.
- UTF-8 이 더 많이 쓰이긴 한다.
- 우리가 사용하는 문자를
비트 (bits)로 나타낸 것이다. 16비트 코드 유닛1개 혹은 2개로 문자를 표현한다.- 1개로 표현되는 경우를
Basic Multilingual Plane내부에 있다고 한다. - 2개로 표현되는 경우를
Basic Multilingual Plane외부에 있다고 한다.
- 1개로 표현되는 경우를
Basic Multilingual Plane (BMP)
Basic Multilingual Plane (BMP)내부에 있는 문자열들은 16비트 코드 유닛 하나로 표현된다.- BMP 안에는 자주 쓰이는 대부분의 문자열이 포함된다.
- 16비트인 만큼, 총 65536 개의 문자를 표현할 수 있다.
대리쌍 (A surrogate pair)
- 1개의 16비트 코드 유닛으로 표현할 수 있는 문자의 최대 개수는 65536 개인데, 전세계의 문자를 표현하기엔 부족한 개수이다.
- 대리쌍 (a surrogate pair) 이라는 것을 더해서 2개의 16비트 코드 유닛을 만들어 모자란 문자를 표현할 수 있다.
- BMP 바깥의 문자는 2개의 16비트 코드 유닛으로 표현된다.
- 두번째 16비트 코드 유닛을
a surrogate pair라고 한다.
코드 포인트 (Code points)
- 모든 유니코드 문자는 유일한
코드 포인트 (Code points)를 할당받는다. - 코드 포인트는 16진수 숫자로 표기된다.
0x0000에서0x10FFFF까지의 범위를 갖는다.- 알파벳
A는0061이라는 코드 포인트를 갖는다. - 코드포인트식 표기로
U+0061이라고 표기된다. - 코드 포인트는 인코딩 스키마와 독립적이다.
- 특정 인코딩에서 문자로 번역되기 위해선 코드 유닛이 되어야 한다.
코드 유닛 (Code Unit)
코드 유닛 (Code Unit)은 특정한 인코딩 스키마에 속한다.코드 포인트 (Code points)를 표기하기 위해 사용된 데이터이다.
예시 보기
- 알파벳,
A- 코드 포인트:
U+0061 - 코드 유닛:
0061
- 코드 포인트:
- 웃는 이모지, 😊
- 코드 포인트
U+1F60A - 코드 유닛:
D83D DE0A
- 코드 포인트
JS 코드로 웃는 이모지 출력해보기
console.log(String.fromCharCode(55357, 56842));
console.log(String.fromCodePoint(0x1f60a));
console.log("\uD83D\uDE0A");
console.log("\u{1F60A}");
- 전부 웃는 이모티콘 (😊) 을 출력한다.
fromCharCode()메서드는 BMP 밖의 코드 포인트를 지원하지 않기 때문에 2개를 합쳐야 한다. (a surrogate pair)fromCodePoint()메서드는 BMP 밖의 코드 포인트도 지원해서 16진수를 한번에 입력해도 된다.\uD83D\uDE0A는 코드 유닛을 이용한 기존의 이스케이프 시퀀스로 표현한 것이다.\u{1F60A}는 유니코드 코드 포인트 이스케이프 시퀀스로 표현한 것이다.
유효하지 않은 대리쌍이란?
다음의 규칙을 따르지 않는 것이다.
- UTF-16 이 표현하려는 문자열 범위 내에 존재하지 않는 16비트쌍을 유효하지 않은 대리쌍이라고 한다.
- 첫번째 16비트 코드 유닛이
0xD800에서0xDBFF범위 내에 없는 것이다. - 두번째 16비트 코드 유닛이
0xDC00에서0xDFFF범위 내에 없는 것이다. - 유니코드 텍스트와 관련된 코드를 짤 때, 유효하지 않은 대리쌍을 넣으면 에러가 발생한다.
관련 메서드 알아보기
String.prototype.codePointAt()
- 문자열에서
코드 포인트(Code points)를 반환해준다.
const charToHex = (str, i) =>
"0x" + str.codePointAt(i).toString(16).toUpperCase().padStart(6, "0");
const str = "😊😊";
console.log("length", str.length);
for (let i = 0; i < str.length; i++) {
console.log("hex", charToHex(str, i));
}
/*
length 4
hex 0x01F60A
hex 0x00DE0A
hex 0x01F60A
hex 0x00DE0A
*/
length로만 따지면, 이모티콘을 2글자로 인식한다.- 이모티콘의
surrogate pair와low surrogate를 순차적으로 출력하고 있다.
- 이모티콘의
- 이 문제를 해결하기 위해서는
for-of루프가 필요하다.
const charToHex = (str) =>
"0x" + str.codePointAt(0).toString(16).toUpperCase().padStart(6, "0");
const str = "😊😍";
for (const emoji of str) {
console.log("hex", charToHex(emoji));
}
/*
hex 0x01F60A
hex 0x01F60D
*/
for-of루프를 이용하면 이모티콘을 1개씩 순회 가능하다.
for (const ch of "> 😊 <") {
console.log(`${ch} (${ch.length})`);
}
/*
> 1
1
😊 2
1
< 1
*/
2개의 UTF-16 코드 단위를 가지는 문자열을 코드 포인터 배열로 변환하는 방법
- 기존의 방법은
str.split("")이었다.- 이 방법은 surrogate pair 를 적절하게 분리하지 못한다는 단점이 있었다.
- 코드 유닛의 배열을 생성한다.
Array.from()을 이용하면 코드 포인트의 배열로 분리가 가능하다.
예제 코드
const codeUnits = "> 😊 <".split("");
const codePointers = Array.from("> 😊 <");
console.log("codeUnits", codeUnits);
console.log("codePointers", codePointers);
출력 결과
codeUnits (6) ['>', ' ', '\uD83D', '\uDE0A', ' ', '<']
0: ">"
1: " "
2: "\ud83d"
3: "\ude0a"
4: " "
5: "<"
length: 6
[[Prototype]]: Array(0)
codePointers (5) ['>', ' ', '😊', ' ', '<']
0: ">"
1: " "
2: "😊"
3: " "
4: "<"
length: 5
[[Prototype]]: Array(0)'자바스크립트 > 개념' 카테고리의 다른 글
| innerHTML vs innerAdajcentHTML() 비교 (0) | 2023.07.15 |
|---|---|
| 자바스크립트 이벤트(Event) 객체와 커스텀 이벤트 (Custom Event) 란? (0) | 2023.07.07 |
| script 태그의 defer 키워드와 async 키워드 쉽게 알아보기 (0) | 2023.02.20 |
| 매크로 태스크 (Macro Task) 와 마이크로 태스크 (Micro Task) 란? (0) | 2023.02.13 |
| 자바스크립트의 실행 컨텍스트 (Execution Context) 란? (0) | 2023.02.05 |