[EXT-031][실무] 깨진 유니코드 문자열 찾아 고치기 > IT 기술 공유

본문 바로가기
사이트 내 전체검색

IT 기술 공유

[EXT-031][실무] 깨진 유니코드 문자열 찾아 고치기

페이지 정보

profile_image
작성자 기술팀장
댓글 0건 조회 10회 작성일 26-09-08 21:35

본문

[이번 수업]
자바스크립트 문자열에 올바른 글자를 만들지 못하는 UTF-16 코드 단위가 섞였는지 확인하고 정리하는 방법을 배웁니다. isWellFormed()는 문자열이 잘 구성됐는지 검사하고, toWellFormed()는 홀로 남은 서로게이트를 대체 문자로 바꾼 새 문자열을 만듭니다.

[선수지식]
문자열과 유니코드 코드 포인트의 뜻을 알고 있으면 됩니다. 코드 포인트는 문자에 붙인 번호이고, UTF-16은 그 번호를 16비트 코드 단위 하나 또는 둘로 표현하는 방식입니다. 모든 자바스크립트 문자열이 정상적인 유니코드 코드 포인트 열이라는 보장은 없습니다.

[학습목표]
1. 서로게이트 쌍과 홀로 남은 서로게이트를 구분할 수 있습니다.
2. isWellFormed()로 문자열 상태를 검사할 수 있습니다.
3. toWellFormed()의 변환 결과와 한계를 설명할 수 있습니다.

[핵심개념]
자바스크립트 String은 16비트 부호 없는 값의 순서이며, 텍스트로 다룰 때 각 값을 UTF-16 코드 단위로 봅니다. 기본 다국어 평면 밖의 이모지 같은 문자는 선행 서로게이트와 후행 서로게이트 두 개가 올바른 순서로 만나 하나의 코드 포인트가 됩니다. 한쪽만 있거나 순서가 어긋나면 잘못 구성된 부분 문자열입니다.

isWellFormed()는 짝 없는 서로게이트가 없으면 true, 있으면 false를 반환하며 원문은 바꾸지 않습니다. toWellFormed()는 짝 없는 선행·후행 서로게이트를 U+FFFD REPLACEMENT CHARACTER, 즉 손상된 글자 자리에 표시하는 대체 문자로 바꿉니다. 올바른 서로게이트 쌍과 일반 글자는 유지합니다. 이 변환은 원래 의도한 글자를 추측해 복원하지 않으며, 대체 후에는 잃어버린 반쪽으로 원문을 되살릴 수 없습니다.

[따라하기]
아래 코드를 unicode-check.js로 저장하세요. `\uD800`은 쌍이 없는 선행 서로게이트를 일부러 만든 학습용 값입니다.

```javascript
const broken = 'A\uD800B';

console.log(broken.isWellFormed());

const fixed = broken.toWellFormed();
console.log(fixed.isWellFormed());
console.log(
  [...fixed]
    .map((ch) => `U+${ch.codePointAt(0).toString(16).toUpperCase()}`)
    .join(' '),
);
console.log(fixed);
```

Windows PowerShell, macOS 터미널, Linux 셸에서 모두 `node unicode-check.js`로 실행합니다. 예상 결과는 다음과 같습니다.

```text
false
true
U+41 U+FFFD U+42
A�B
```

대체 문자의 모양은 터미널과 글꼴에 따라 네모나 마름모처럼 보일 수 있지만, U+FFFD 출력으로 값을 확인할 수 있습니다. 오래된 환경에서는 기능 지원 여부를 확인하고 런타임 갱신이나 검증된 폴리필을 검토하세요.

[흔한 실수]
첫째, length가 글자 수라고 생각합니다. UTF-16에서 보조 평면 문자는 코드 단위 둘을 사용할 수 있습니다. 둘째, normalize()가 짝 없는 서로게이트를 고친다고 기대합니다. 유니코드 정규화와 문자열 구성 검사는 다른 문제입니다. 셋째, toWellFormed()이 원본을 직접 수정한다고 생각합니다. 문자열은 불변이므로 반환값을 저장해야 합니다. 넷째, 모든 입력을 조용히 변환해 데이터 손상 원인을 숨깁니다.

[보안 주의]
이 검사는 HTML 삽입, SQL 삽입, 경로 조작을 막는 보안 필터가 아닙니다. 출력 위치에 맞는 인코딩과 안전한 API는 별도로 적용하세요. 사용자 표시 문구는 정책에 따라 U+FFFD로 정리할 수 있지만, 식별자·서명 대상·해시 입력처럼 정확한 값이 중요한 데이터는 자동 수정하지 말고 거부하거나 원본과 오류를 분리해 기록해야 합니다. 길이 제한도 코드 단위, 코드 포인트, 사용자가 보는 글자 중 무엇을 세는지 명시하세요. 실습은 본인 소유의 로컬 데이터에서만 수행합니다.

[직접 해볼 과제]
정상 이모지 `\uD83D\uDE00`, 홀로 있는 선행 서로게이트 `\uD83D`, 홀로 있는 후행 서로게이트 `\uDE00`을 각각 문자열로 만들고 isWellFormed() 결과를 비교하세요. 잘못된 두 문자열에 toWellFormed()을 적용한 뒤 코드 포인트가 U+FFFD인지 확인하세요.

[확인문제]
1. UTF-16 서로게이트 쌍은 어떤 두 코드 단위로 이루어집니까?
2. isWellFormed()과 toWellFormed()의 가장 큰 차이는 무엇입니까?
3. 식별자나 서명 대상 문자열을 무조건 toWellFormed()으로 바꾸면 안 되는 이유는 무엇입니까?

[다음 학습]
다음에는 TextEncoder와 TextDecoder로 문자열과 UTF-8 바이트를 오가고, 디코딩 오류를 대체할지 거부할지 선택하는 방법을 배웁니다.

[공식 참고 자료]
ECMAScript 2025 String 타입과 UTF-16
https://tc39.es/ecma262/2025/multipage/ecmascript-data-types-and-values.html#sec-ecmascript-language-types-string-type
ECMAScript 2025 String.prototype.isWellFormed
https://tc39.es/ecma262/2025/multipage/text-processing.html#sec-string.prototype.iswellformed
ECMAScript 2025 String.prototype.toWellFormed
https://tc39.es/ecma262/2025/multipage/text-processing.html#sec-string.prototype.towellformed

댓글목록

등록된 댓글이 없습니다.

회원로그인

회원가입

사이트 정보

회사명 : 회사명 / 대표 : 대표자명
주소 : OO도 OO시 OO구 OO동 123-45
사업자 등록번호 : 123-45-67890
전화 : 02-123-4567 팩스 : 02-123-4568
통신판매업신고번호 : 제 OO구 - 123호
개인정보관리책임자 : 정보책임자명

접속자집계

오늘
4,746
어제
6,862
최대
16,772
전체
770,697
Copyright © 소유하신 도메인. All rights reserved.