1. 개요
UTF-8은 가장 많이 사용되는 가변 길이 유니코드 인코딩이다. 켄 톰슨과 롭 파이크( Go 언어를 만든 사람)가 만들었다. UTF-8이란 말은 Unicode Transformation Format - 8bit에서 유래했다고.2. 상세
코드 페이지는 65001로, UTF-8로 표현 가능한 길이는 최대 6바이트지만[1] 다른 인코딩과의 호환을 위해 4바이트까지만 사용한다. 그래서 한 글자가 1~4바이트 중 하나로 인코딩될 수 있으며, 1바이트 영역은 아스키 코드와 하위 호환성을 가진다. 아스키 코드의 0~127까지는 UTF-8로 완전히 동일하게 기록된다. 어차피 유니코드는 U+10FFFF까지만(10진법으로는 1,114,111) 이용하는데, UTF-8은 아래에 나와 있듯이 가변 바이트 길이를 선언하기 위해 꽤 많은 비트를 잡아먹고도 2,097,151까지 인코딩할 수 있기 때문에 4바이트만으로도 충분하고도 남는다.이런 장점으로 인해 인터넷 사이트에서 가장 많이 쓰이는 인코딩이다. 유니코드가 널리 쓰이기 전부터 형성된 인터넷 문서들은 대부분 아스키 코드를 기본으로 해서 작성되었고, 특히 기존의 HTML 태그나 자바스크립트 등 아스키로 구축된 사이트를 별다른 변환 처리 없이 그대로 쓸 수 있는 엄청난 장점이 있었다. 더군다나 UTF-8은 엔디언에 상관없이 똑같이 읽을 수 있으므로 크로스플랫폼 호환성도 뛰어났다. 과거 한국에서는 국가별 인코딩인 EUC-KR을 쓰던 사이트들이 많이 남아 있어서, 한때는 각종 브라우저에서 '주소를 UTF-8로 보냄' 옵션을 체크 해제하는 팁(주로 한글 이름으로 된 파일의 링크를 클릭해서 404 에러가 뜰 때)이 널리 퍼졌다. 지금은 일부 구닥다리 사이트를 제외하면 UTF-8로 옮겨 가는 추세이며 관공서 사이트도 차츰 UTF-8 기반으로 바뀌고 있다. 그리고 요즘은 EUC-KR을 사용하더라도 서버 측에서 자동으로 변환해 주도록 처리하기 때문에 큰 문제가 되지 않는다.
UTF-16 인코딩을 사용하면 1바이트로도 표현할 수 있는 문자에 그보다 더 많은 바이트를 소비해야 하는데, UTF-8 인코딩을 사용하면 그런 문제점이 없다. 그러나 한자나 한글은 주로 3바이트 영역에 집중되어 있기 때문에 거의 모든 문자에 균일하게 2바이트만 사용하는 UTF-16에 비해 오히려 크기가 커진다. 그래서 한글로 작성된 파일의 경우 EUC-KR이나 UTF-16에 비해서 파일 크기가 최대 1.5배로 늘어난다. 그러나 용량 문제는 일단 압축하면 다른 인코딩과 별 차이 없는 데다 텍스트가 아무리 커져 봐야 얼마 안 되기 때문에 이미지/영상/빅 데이터 시대에 아무 문제가 안 된다. 현대적인 오피스 파일 형식은 내부적으로 압축 파일을 컨테이너로 사용하기 때문에 체감 차이는 더 적어진다. 웹 페이지나 XML 같은 소스 코드류 파일의 경우 한글과 다수의 로마자가 섞여 있기 때문에 EUC-KR로 작성된 파일을 UTF-8로 변환해도 파일 크기가 크게 늘어나지는 않는다. 오히려 UTF-16에서 UTF-8로 변환하면 데이터 크기가 줄어드는데, 한글은 2바이트가 3바이트가 되지만, 로마자는 2바이트가 1바이트로 줄어들기 때문. 통계 인터넷으로 전송할 때에도 요새는 기본적으로 웹 서버에서 압축해서 전송하기 때문에 압축해 놓고 보았을 때는 큰 차이가 없어진다. 물론 이 소량의 용량 증가에 주의해야 될 상황이 있기는 하지만[2] 일반적인 경우는 아니다.
그럼에도 불구하고 세계적으로는 UTF-8 인코딩이 가장 널리 쓰이기 때문에 유니코드를 지원하는 대부분의 프로그램들은 일단 UTF-8을 디폴트 상태로 지정해 주는 경우가 많다. 웹 등지에서 유니코드 적용이 서구권을 중심으로 퍼졌기에 서구권 입장에서는 기존 8비트 코드(1바이트 아스키 코드)와 호환성이 있는 UTF-8을 많이 선택했고, 결국 이것이 대세가 된 것이다.
ASCII 호환성, C로 작성된 Unix 프로그램 호환성, BOM이 필요 없다든가, 엔디언을 따지지 않아도 된다든가, 파싱에 예외 모드 확장 문자 처리 등등이 필요 없고, 그 덕에 실체 처리 속도도 더 빠르다든가 하는 엔지니어링 측면에서의 수많은 장점도 존재한다.
다른 장점들도 많지만 무엇보다도 혼동의 여지가 없는 단일 인코딩 방식이라는 게 가장 중요하다. UTF-16은 하위 인코딩 문제가 매우 심각했는데, 인코딩에 여러 하위 방식이 존재해 읽을 때마다 그냥 UTF-16이라고만 하면 절대 디코딩을 할 수 없었다. 대표적으로 endian 문제가 있다. big-endian에서는 바이트를 본래 순서로 저장하지만, little-endian에서는 순서가 뒤바뀐다. 그래서 endian을 혼동하면 전혀 다른 글자가 튀어나오거나 오류가 발생하며, 이 때문에 BOM을 붙이도록 되어 있다. 또 UTF-16의 하위 호환인 UCS-2라는 것도 존재하는데, SMP 영역의 문자가 포함된 UTF-16 문서를 UCS-2로 읽어들이면 문제가 생긴다. 그런 UTF-16과 달리 UTF-8은 인코딩이 딱 한 가지만 존재하고 다른 방식으로 실수할 여지 자체가 없다. EUC-KR, Shift_JIS, EUC-JP, GB2312, Big5 등 난립하는 자국어 인코딩으로 수십 년간 피를 본 동아시아권 개발자들에게도 단 한 가지 인코딩 방식만 존재하는 UTF-8은 신이 내린 선물이나 다름없었고, 그래서 동아시아권에서 더 강력한 지지가 나왔다. 한국어 인코딩만 해도 3~4가지가 넘었고 미묘하게 비슷한 것도 존재해서 미묘하게 깨지는 경우가 많았다. 어차피 2바이트 영역에 자국 문자를 다 담을 수조차 없는 중국어권도 마찬가지.
오히려 MS, 애플 등의 서구권 기존 대기업들이 UTF-16을 고수했는데, 왜냐면 UTF-8이 개발되기 전에 UTF-16으로 유니코드/국제화 지원을 다 만들어놔서 바꾸기가 매우 힘들었기 때문이다. 현재는 압도적인 장점으로 만들어진 대세 앞에 슬슬 옮기는 추세다. 애플은 CoreText나 스위프트 5.x에서 UTF-8로 공식적으로 넘어갔지만 레거시의 MS답게 MS의 저항은 여전하다. 심지어 윈도우는 호환성을 이유로 대부분의 영역에서는 아직도 MBCS를 쓰고 있는 실정이다. 마이크로소프트 역시 Windows 10 출시 이후로 서서히[3] 넘어가는 추세이긴 하지만 호환성 문제 때문에 완벽하게 넘어가지는 못하는 상황이다.[4]
3. 인코딩
규칙- 1개 바이트를 사용:
- 가장 큰 비트에 0을 할당하고, 나머지 7비트에 기존의 아스키 코드를 모두 할당한다. 0xxxxxxx값을 모두 사용하였다. (아직 1xxxxxxx는 사용 가능한 상황이다.)
- 사용하려는 바이트가 2개가 넘을 때: 첫 바이트에는 몇 바이트를 사용하는지 알려주는 비트를 먼저 넣는다.
- 2바이트(110), 3바이트(1110), 4바이트(11110)
- 나머지 바이트에는 여러 바이트에서 연결되었음을 알리는 비트를 먼저 넣는다. 이때 2바이트 표식을 넣은 데이터와 겹치지 않도록, 10이라는 비트를 넣어준다.
- 표식 비트가 아닌 나머지 비트들은 모두 데이터 비트로 사용한다.
규칙이 실제로 적용된 값의 표:
바이트에서 1과 0으로 표현된 자리는 바이트 크기 표시(고정), x 자리는 전부 데이터 비트(변동)이다.
유니코드 | utf-8로 저장하는 값 | ||||||
자릿수 | 코드값 범위 | 첫 바이트 | 둘째 바이트 | 셋째 바이트 | 넷째 바이트 | 다섯째 바이트 | 여섯째 바이트 |
00~07비트 | 0 ~ [ruby(0x7F, ruby=127)] | 0xxxxxxx | |||||
08~11비트 | [ruby(0x80, ruby=128)] ~ [ruby(0x7FF, ruby=2\,047)] | 110xxxxx | 10xxxxxx | ||||
12~16비트 | [ruby(0x800, ruby=2\,048)] ~ [ruby(0xFFFF, ruby=65\,535)] | 1110xxxx | 10xxxxxx | 10xxxxxx | |||
17~21비트 | [ruby(0x10000, ruby=65\,536)] ~ [ruby(0x1FFFFF, ruby=2\,097\,151)][5] | 11110xxx | 10xxxxxx | 10xxxxxx | 10xxxxxx | ||
22~26비트 | (미사용)[6] | 111110xx | 10xxxxxx | 10xxxxxx | 10xxxxxx | 10xxxxxx | |
27~31비트 | (미사용)[7] | 1111110x | 10xxxxxx | 10xxxxxx | 10xxxxxx | 10xxxxxx | 10xxxxxx |
이 테이블을 이용해 각각의 유니코드 문자를 UTF-8로 표현해 보면 다음 그림과 같다.
- 예시 1: 문자 A는 아스키 문자이며 유니코드값은 65로, 이는 16진수 0x41(0100 0001)인데, 7비트 이내로 표현 가능하므로 UTF-8로도 0x41로 표현된다.
- 예시 2: 문자 π는 유니코드값이 7비트를 벗어난다. 그러나 11비트 이내에 표현이 가능한 비교적 앞쪽에 위치한 문자며, 따라서 그림과 같이 2바이트에 표현이 가능 하다.
- 예시 3: 문자 한은 한글 문자로 16비트를 모두 사용한다. 마지막 16비트가 1이며 따라서 이를 표현하기 위해서는 그림과 같이 3바이트를 사용해야 한다. 참고로 유니코드에는 완성형 한글 11,172자뿐만 아니라 조합형 자모가 모두 포함되어 있으며, 이처럼 한글의 UTF-8 인코딩값은 모두 각 문자당 3바이트를 차지한다.
UTF-8로 변환된 유니코드 문자 그룹과 개수
크기 | 유니코드 영역 | 개수 | 예시 |
1바이트 | U+0000~U+007F | 127개 | 아스키 코드 전체 |
2바이트 | U+0080~U+07FF | 1920개 | 일부 문자[목록1] |
3바이트 | U+0800~U+FFFF | 6만여 개 | 대부분의 문자들[목록2] |
4바이트 | U+10000~U+10FFFF[10] | 미확인 | BMP에 속하지 않는 문자 전부 |
- 한글 조합형 자모는 U+1100~11FF[11] 영역에 위치한다.
- 한글 완성형 자모는 U+3130~318F 영역에 위치한다.
- 한글 완성형 글자는 U+AC00~D7A3[12] 영역에 위치한다. 예를 들어 '갑'의 유니코드값은 16진수 0xAC11(1010 1100 0001 0001)인데, 이는 총 16비트가 필요하므로 1110 1010 1011 0000 1001 0001 으로 표현한다.
- 완성형 글자 하나도 3바이트인데, 조합형은 자모 하나하나가 각각 3바이트씩(글자 하나당 6~9바이트) 사용한다. 따라서 일반적으로 완성형 글자를 사용하고, 조합형은 완성형에 없는 옛한글 등을 쓰기 위해서 사용하는 것이 효율이 좋다.
4. 문서에의 UTF-8
UTF-8이 대세긴 하지만 프로그램 내부적인 처리에서는 다른 인코딩을 얼마든지 써도 된다. 예를 들어 MS 계열 프레임워크에서 네이티브 언어( C/ C++ 등)를 이용해 비유니코드의 멀티바이트 캐릭터를 UTF-8 형식으로 변환하기 위해서는 와이드바이트 형식의 2바이트 유니코드 인코딩(ucs2)으로 변환한 다음 다시 UTF-8 플래그를 주어 멀티바이트 형식으로 다시 변환하는 과정이 필요하다. 그리고 리눅스와 같은 MS 프레임워크 이외의 플랫폼에서도 명시적이지만 않을 뿐이지 내부적으로는 유니코드로 변환한 후 처리되는 과정이 포함되어 있다. 리눅스는 UTF-8을 네이티브로 사용한다.한글 단어가 UTF-8 형식으로 어떻게 나올 것인지 궁금하다면 메모장과 같은 텍스트 에디터로 단어를 써서 UTF-8 형식으로 저장한 후 헥스 에디터를 이용하여 보면 된다. 다만 메모장을 쓸 경우 헥스 에디터로 열었을 때 EF BB BF라는 문자가 파일 가장 앞에 붙는다. 이것을 BOM(Byte Order Mark)이라고 하는데 이건 빼고 그 뒤부터 보면 된다. 다만 서버사이드 스크립트에서 헤더 요청을 할 때에는 상황이 달라진다. 보통 헤더 요청(주로 로그인 상태 유지를 위한 세션에 쓰임)은 출력이 있기 이전에 처리되어야 하는 사항인데, BOM이 있으면 그것이 출력이 되어 버리기 때문에 헤더 요청이 전부 도로 아미타불이 되어버린다. 더욱이 BOM은 보이지도 않는다. 그래서 서버사이드 스크립트는 절대로 메모장으로 작업하지 않는다. 참고로 UTF-8이 아닌 유니코드 자체의 BOM은 U+FEFF이며, little-endian 방식에서는 FF FE가 될 수 있다. 해독할 때는 퍼센트 기호를 빼고 헥스 에디터에 그대로 쓴 다음 저장한 뒤 텍스트 에디터로 읽으면 된다. BOM은 각각 몇 가지 종류가 있고, 파일에 BOM이 써질 수도 있고 안 써질 수도 있으며, 유닉스/리눅스 계열에서는 쓰지 않는 것이 관례이므로 상황에 맞게 코딩 또는 변환을 하는 것이 필요하다. 특히 웹 프로그래밍을 할 때는 BOM을 안 쓰는데, 소스 코드 파일 여러 개가 합쳐져서 하나의 웹 페이지를 구성하는 경우가 많다 보니 BOM이 있으면 파일들이 합쳐질 때 코드를 잘못 인식해서 에러가 나기 때문이다.
마이크로소프트의 제품군이 UTF-8에 BOM을 붙여 인코딩하는 것은 유니코드 컨소시엄에서 권장하지 않는 방법이다. 2.6 Encoding Schemes 사실 UTF-8은 굳이 endian을 따지면 big-endian 방식 고정이기 때문에 BOM의 존재 자체가 의미가 없기 때문이다. 그런데 Visual Studio는 상황이 좀 달라서, 소스 코드에 하드코딩된 유니코드 문자열이 있는 경우, BOM이 존재하지 않으면 ANSI 또는 시스템 코드 페이지로 소스 코드를 읽어들여 비ASCII 문자열에 대해 오류가 나거나 코드 자체를 인식하지 못하는 경우가 존재한다. 그러므로 Visual Studio에서 문자열(특히 한글)을 정상적으로 출력하고 싶으면 소스 파일의 인코딩을 UTF-8 BOM으로 설정해야 한다. 반대로, GCC의 경우 BOM이 있으면 에러를 내기 때문에 소스 파일은 UTF-8로 설정해야 한다.
운영 체제 자체의 인코딩 형식을 UTF-8로 통일한 리눅스나 macOS와 달리 윈도우는 레거시 호환을 위해 콘솔 인코딩으로 MBCS를 계속 사용하고 있어, GCC를 기반으로 윈도우 환경에서 C/C++ 같은 네이티브 언어를 이용하여 UTF-8 소스의 한글 출력을 하려면 여러 가지 애로 사항이 꽃핀다. 우선 한 가지 방법으로는 컴파일 옵션에 -fexec-charset=CP949를 추가하는 것이 있다. 하지만 이렇게 특정 코드 페이지를 직접 지정하면 OS 언어와 컴파일러에 의존적인 소스 코드가 되어버린다.
또 하나의 방법은 문자열 관련 코드를 작성할 때 wchar_t, wprintf() 등의 와이드바이트 자료형 및 함수를 사용하는 것이다. main 함수 내에
setlocale(LC_ALL, "")
함수 선언이 필요하다. wprintf() 서식 지정자의 경우 MinGW-GCC는 C에서 %s, C++에서 %S이고 VC++는 양쪽 모두 %s이다. 윈도우의 경우
윈도우 API의 _setmode(_fileno(stdout), _O_U16TEXT)
를 대신 사용해도 된다.
# 다만, 이 경우 입력 및 출력 시에는 무조건 유니코드 함수만 사용해야 한다. 하지만 wchar_t는 운영 체제에 따라 자료형의 크기가 달라 차후 이식성에 문제가 있다. 윈도우에서의 기본값은 2바이트이고 리눅스에서의 기본값은 4바이트인데, 컴파일 옵션 -fshort-wchar를 지정하면 크기를 2바이트로 통일시킬 수 있지만 wchar_t를 사용하는 표준 라이브러리 파일의 정상적인 실행을 보장할 수 없다. 따라서 그냥 크로스컴파일을 포기하고 wchar_t를 쓰거나,
ICU라는 캐릭터 셋 변환 라이브러리를 사용하는 것이 현재로서는 최선의 해답이다. 대신 ICU는 빌드 과정이 매우 복잡하다.
GNU의 libiconv를 사용하면 상당히 가벼워지지만, 라이브러리를 정적으로 링크할 경우[13]
라이선스 문제가 생길 수 있다. 윈도우 인사이더 프리뷰 17035(1803 버전)부터 '시스템 로캘 변경' 옵션에 'Beta: 세계 언어 지원을 위해 Unicode UTF-8 사용'이 추가되었다. #
윈도우 10 1903 버전의 메모장에서 BOM 없는 UTF-8이 기본 인코딩으로 변경되었으며, 저장 시 BOM을 붙일지 선택할 수 있게 변경되었다. 다만 BOM 없는 UTF-8 문서 자체는 기존 메모장( 윈도우 XP 이상)에서도 잘만 읽어낸다.
C++의 기능을 사용할 경우 유니코드 자료형을 사용할 수 있다. UTF-8 자료형의 경우에는 char 자료형에서 리터럴을 u8" "로 선언하면 된다. 향후 C++20에서 UTF-8 단독 자료형인 char8_t가 추가될 예정이다. UTF-16의 경우에는 char16_t 자료형에서 u" "로 선언하면 되고, UTF-32의 경우에는 char32_t 자료형에서 U" "로 선언하면 된다. 단, 컴파일러에 종속적인 인코딩을 사용하지 않으려면 매크로를 이용해
__STDC_UTF_8__
, __STDC_UTF_16__
, __STDC_UTF_32__
를 1로 정의해야 한다. 윈도우에서는 UTF-8 문자열을 직접 입출력할 수 없었지만,
윈도우 인사이더 프리뷰 17035(1803 버전)부터 콘솔의 코드 페이지를 65001로 설정하는 함수를 통해 가능해졌다. 단, 입력과 출력만 UTF-8로 변경될 뿐,
표준 라이브러리의 (wchar_t
를 인자로 받지 않는) 비유니코드 함수들은 전부 운영 체제의 코드 페이지를 따르기 때문에,
정규표현식과 같은 기능이 UTF-8 문자열을 제대로 처리하지 못한다. 이것까지 제대로 처리되게 하려면 위에서 언급한 윈도우 UTF-8 베타 옵션을 활성화해야 한다.한글 페이지를 일본어 인코딩으로 해석하거나, 그 반대의 경우 등은 UTF-8이 아닌, 각 국가별 인코딩(EUC-KR, Shift-JIS 등)을 사용해서 발생하는 경우가 많다. 물론 유니코드 페이지도 다른 인코딩으로 지정하면 깨진다.
웹 페이지에서 인코딩 선언을 해주는 건 기본 중의 기본임에도 불구하고, 그 기본을 지키지 않아서 글자가 깨지는 문제로 사용자가 수동으로 인코딩을 지정하게 하는 경우가 많다. Microsoft Edge 등 이 기능을 빼먹은 브라우저도 있다. 크롬 역시 업데이트를 통해 인코딩 지정이 빠지고 자동으로 선택되도록 바뀌었는데, 이 때문에 일부 페이지를 EUC-KR이나 Windows-1252(서유럽어)로 잘못 해석하는 경우가 더러 있다. 웹 페이지의 소스를 보면 <meta http-equiv="content-type" content="text/html; charset=UTF-8" /> 이렇게 적힌 부분이 있는데 여기서 charset=UTF-8 부분이 인코딩 선언이다.[14] 어떤 웹 페이지에는 UTF-8 대신에 EUC-KR이나 Shift_JIS 등이 적혀있기도 하다. HTML5부터는 <meta charset="UTF-8">과 같이 간단하게 쓸 수도 있다.
5. URL에서 UTF-8
- namu.wiki/w/유니코드
- namu.wiki/w/%EC%9C%A0%EB%8B%88%EC%BD%94%EB%93%9C
- %EC%9C%A0 = 유 (UTF-8: 0xEC 0x9C 0xA0)
- %EB%8B%88 = 니 (UTF-8: 0xEB 0x8B 0x88)
- %EC%BD%94 = 코 (UTF-8: 0xEC 0xBD 0x94)
- %EB%93%9C = 드 (UTF-8: 0xEB 0x93 0x9C)
URL에서 알파벳과 숫자 및 일부 특수 문자 영역 밖의 문자를 사용할 때 URL escape code를 통해서 문자열을 인코딩해서 표시한다. URL escape code는 임의의 바이너리 데이터를 전송할 때 사용하는 것으로, 이들 이외의 문자열이 URL에 포함되어 있을 때 처리 방식은 엄밀하게 정의되어 있지 않으며 웹 브라우저에 따라 어떻게 인코딩할지 정책이 다르다. 즉, URL escape code로 인코딩되었다고 하여 항상 UTF-8로 인코딩된 유니코드 문자열이 왔다는 보장은 없다.
2000년대 초반에 그림 등이 제대로 보이지 않으면 'URL을 항상 UTF-8로 보내기' 옵션을 끄라는 말이 많이 나왔는데, 과거의 웹 개발자들이 퍼센트 인코딩, 유니코드, 문자 인코딩 등에 큰 신경을 쓰지 않았던 시절의 흔적이다. 퍼센트 인코딩을 적용시키지 않은 문자열이 URL 내부에 온 경우 저 옵션이 켜져 있으면 URL에 올 수 없는 문자열을 UTF-8로 인코딩한 값을 퍼센트 인코딩을 적용시켜서 웹 서버에 요청하지만, 한때는 상당수 웹 서버가 EUC-KR 기반이었기 때문에 UTF-8 문자열이 오면 파일을 제대로 찾을 수 없는 문제가 있었다. 저 옵션을 꺼 버리면 EUC-KR로 URL 인코딩해 보내기 때문에 파일을 웹 서버에서 제대로 찾게 된다. 지금은 웹 브라우저와 웹 서버가 모두 UTF-8를 가정하고 개발되는 경우가 많으며, EUC-KR 등 굳이 다른 인코딩을 사용하고 싶으면 웹사이트 쪽에서 알아서 URL 인코딩해 주는 경우가 대부분이다. 오히려 지금은 UTF-8로 보내기 옵션이 꺼져 있으면 문제가 발생하는 경우가 있기 때문에 저 옵션을 켜라고 하는 웹사이트들도 존재한다.
물론 이건 파일이나 경로명이 한글일 경우에만 그랬고, 영문일 경우에는 옵션이 켜져 있건 꺼져 있건 문제없이 찾는다. UTF-8의 1바이트 영역과 EUC-KR의 1바이트 영역은 아스키 코드와 일치하기 때문이다. 그래서 일부 웹사이트에서는 파일을 올릴 때 서버에서 지정한 이름으로 바꿔서 올라가도록 설계하기도 했다.
서버에 파일을 올리고 난 뒤에 파일명이 이상하게 바뀔 때 UTF-8 방식으로 인코딩된 것일 경우가 많다. ASCII 영역 밖 문자들이 치환되다 보니, 공백이나 특수 문자의 경우 많이 치환되는 편이며, 용도에 따라 URL용 특수 기호는 치환될 때도, 치환되지 않을 때도 있다.[15] 주로 치환되는 문자들을 나열하자면 다음과 같다.
- 공백(space): %20[16]
- !: %21
- (: %28
- ): %29
- +: %2B
- -: %2D
- /: %2F
- [: %5B
- ]: %5D
- _: %5F
6. 문자 깨짐
Internet Explorer와 구버전 Microsoft Edge[17]에서는 UTF-8로 저장된 파일을 다운로드할 때 EUC-KR로 읽어들여서 문자 깨짐이 발생한다. 하지만 크롬이나 파이어폭스에서는 멀쩡하게 나온다.UTF-8로 작성된 파일을 복구 프로그램등으로 읽어 보면 뷁어가 나온다. 이는 윈도우 기본 설정이 CP949로 설정되어 있기 때문이며 해당 뷁어를 복사하여 UTF-8로 디코딩하면 일부 단어만 정상적으로 출력된다.[18] 메모장 기본 설정이 UTF-8이라 이런 경우가 꽤 있다.
윈도우상에서 UTF-8 인코딩을 활성화해 준 뒤 재부팅해야 한다.
7. 관련 문서
[1]
이론상 U+7FFFFFFF까지 표현 가능하다. 포인트 수가 2,147,483,648개이므로 표현 가능한 글자 수는 대략 21억여 글자이며, 1개 평면당 65,536개의 포인트가 있으므로 최대 32,768개의 평면까지 가능하다.
[2]
예를 들면 DB 테이블에 바이트 수가 제한되어 있는데 들어 있는 데이터를 EUC-KR에서 UTF-8로 변환하면 바이트 수가 커지기 때문에 뒷부분이 짤리거나 하는 현상이 발생한다.
[3]
윈도우 10부터 메모장의 기본 저장 형식이 UTF-8로 설정되었다.
[4]
Windows 프로그램에 사용되는 수많은 API들이 비유니코드 버전인 ASCII와 유니코드 버전(UTF-16 LE)의 두 가지로 분류되어 구축되어 있기 때문. 유저가 UTF-8을 사용하는 것은 문제가 없지만 윈도우 내부적으로는 모든 API가 UTF-16 구조의 문자열을 기본으로 해석하도록 짜여 있기에, 바꾸었다가는 기존에 개발된 프로그램들의 문자가 모두 깨져버린다.
[5]
유니코드 범위는 [ruby(0x10FFFF, ruby=1\,114\,111)] 까지만 쓰며, [ruby(0x110000, ruby=1\,114\,112)] 부터는 쓰지 않는다.
[6]
이론상의 코드값 범위는 [ruby(0x200000, ruby=2\,097\,152)] ~ [ruby(0x3FFFFFF, ruby=67\,108\,863)]이다.
[7]
이론상의 코드값 범위는 [ruby(0x4000000, ruby=67\,108\,864)] ~ [ruby(0x7FFFFFFF, ruby=2\,147\,483\,647)]이다.
[목록1]
유니코드/0000~0FFF의 일부. 제어 문자, 라틴어, 음성 기호, 조정 문자, 결합 문자, 그리스어, 키릴 문자(러시아어 등), 아르메니아어, 히브리어, 아랍어, 시리아어, 타나 문자(몰디브), 은코 문자(아프리카)
[목록2]
사마리아 문자~.
유니코드/0000~0FFF의 일부부터
유니코드/F000~FFFF까지에 속한다.
[10]
4바이트의 경우 이론상 U+1FFFFF까지 표현 가능하나 가용 범위는 U+10FFFF까지이다.
[11]
10진법으로 4,352~4,607
[12]
10진법으로 44,032~55,203
[13]
하나의 실행 파일에 전부 포함하는 것이라고 보면 된다.
[14]
text/html 대신에 application/xhtml+xml 이 적힌 곳도 있고 아예 다른 게 있을 수도 있다.
[15]
자바스크립트 기준으로 모두 치환하면 escape() 메서드를, URL용 : / ; ? 를 남기려면 encodeURI()나, encodeURIComponent() 메서드를 쓰며, 그 결과로 이렇게 된다.
[16]
+나 _로 인코딩되는 경우도 있다.
[17]
2019년부터는 크로뮴 기반으로 변경되어 해당 사항이 없다.
[18]
예를 들면 갈푼.