자바스크립트의 문자열 표현 방식 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 |