UTF-8

 

1. 개요
2. 상세
3. 인코딩
4. 문서에의 UTF-8
5. URL에서 UTF-8
6. 관련 문서


1. 개요


UTF-8은 가장 많이 사용되는 가변 길이 유니코드 인코딩이다. 켄 톰슨과 롭 파이크(Go 언어를 만든 사람)가 만들었다. UTF-8이란 말은 Unicode Transformation Format - 8bit에서 유래했다고.

2. 상세


코드 페이지는 65001로, UTF-8로 표현 가능한 길이는 최대 6바이트지만 다른 인코딩과의 호환을 위해 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에 비해 오히려 크기가 커진다. 그럼에도 불구하고 세계적으로는 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#s-5 영역의 문자가 포함된 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바이트 구간에 존재한다. 그래서 한글로 작성된 파일의 경우 파일 크기가 최대 1.5배로 늘어난다. 다만 웹 페이지나 XML 같은 소스코드류의 파일의 경우 한글과 다수의 로마자가 섞여 있기 때문에 EUC-KR로 작성된 파일을 UTF-8로 변환해도 파일 크기가 크게 늘어나지는 않는다. 오히려 UTF-16에서 UTF-8로 변환하면 데이터 크기가 줄어드는데, 한글은 2바이트가 3바이트가 되지만, 로마자는 2바이트가 1바이트로 줄어들기 때문. 통계 그래도 용량이 신경 쓰인다면 "NTFS 폴더 압축" 등의 OS에서 제공하는 디스크 관리 기능으로 효율성을 높일 수 있다. 인터넷으로 전송할 때에도 요새는 기본적으로 웹 서버에서 압축해서 전송하기 때문에 압축해 놓고 보았을 때는 큰 차이가 없어진다.

3. 인코딩


7비트 이내의 코드값(0-127)에는 맨 앞 비트를 0으로 붙인다. 아스키 코드에 해당하는 0번부터 127번까지의 문자 128개는 정확하게 7비트로 표현 가능하다. 1바이트는 8비트이므로, 맨 앞에 0을 붙이고 나머지 7비트를 사용해 127까지를 기록한다. 00000000은 아스키 코드 0번에 해당하며, Null(통칭 '널문자')을 뜻한다.
7비트 초과, 11비트 이내의 코드값(128 ~ 2,047)은 총 2바이트로 표현한다. 먼저 가장 앞에 0 대신 1을 써서 이 문자가 1바이트를 초과한다는 것을 선언한 뒤, 1을 하나 더 써서 이 뒤에는 1개의 바이트가 추가로 온다고 선언한다. 마지막으로 0을 써서 선언을 종료하면 첫 3비트는 110이 된다. 남은 5비트는 문자 인코딩에 사용한다. 그 다음 두 번째 바이트는 맨 앞 2비트로를 10을 써서 이 바이트는 독립적인 문자가 아닌 전 바이트의 후속 바이트라는 것을 명시해주고 남은 6비트를 문자 사용에 배당한다. (8-3+8-2=11)
11비트 초과, 16비트 이내의 코드값(2,048-65,535)에는 총 3바이트를 사용한다. 이번에는 맨 앞에 1을 써서 1바이트 초과를 선언하고, 1을 두 개 더 써서 후속 바이트가 2개라고 선언하고, 0을 써서 선언을 종료한 뒤(1110) 남은 4개의 비트를 문자 표기에 사용한다. 후속 바이트 2개는 맨 앞에 10을 써서 후속 바이트임을 명시해 주고, 남은 6비트씩을 문자 인코딩에 사용한다. (8-4+8-2+8-2=16)
마지막으로 4바이트를 사용해야 하는 경우(65,536-2,097,151)에는 맨 앞 바이트에는 1을 4개 쓰고 0을 쓴 뒤 남은 3개 비트로 문자를 표기, 후속 바이트 3개는 위의 후속 바이트들과 같은 방식으로 각각 6개씩의 가용 비트를 제공해 준다.
이걸 정리하면 다음과 같다.
코드값의 자릿수
범위
첫 바이트
둘째 바이트
셋째 바이트
넷째 바이트
다섯째 바이트
여섯째 바이트
7비트
0 ~ 0x7F(127
0xxxxxxx





11비트
0x80(128 ~ 0x7FF(2\
110xxxxx
10xxxxxx




16비트
0x800(2\ ~ 0xFFFF(65\
1110xxxx
10xxxxxx
10xxxxxx



21비트
0x10000(65\ ~ 0x1FFFFF(2\
11110xxx
10xxxxxx
10xxxxxx
10xxxxxx


26비트
(미사용)
111110xx
10xxxxxx
10xxxxxx
10xxxxxx
10xxxxxx

31비트
(미사용)
1111110x
10xxxxxx
10xxxxxx
10xxxxxx
10xxxxxx
10xxxxxx
이 테이블을 이용해 각각의 유니코드 문자를 UTF-8로 표현해보면 다음 그림과 같다.
[image]
<파이썬 알고리즘 인터뷰> p.164, 책만, 2020
  • 예시 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바이트를 차지한다.
한글 완성형은 유니코드 상으로 U+AC00~U+D7A3이므로, 10진법으로는 44,032~55,203의 영역이고, 따라서 3바이트를 차지한다. 예를 들어 '갑'의 유니코드값은 16진수 0xAC11(1010 1100 0001 0001)인데, 이는 총 16비트가 필요하므로 1110 1010 1011 0000 1001 0001 으로 표현한다. 조합형은 U+1100~11FF 영역인데, 여기도 4,352~4,607이라 결국 3바이트 영역이다. 완성형 글자 하나도 3바이트인데, 조합형은 자모 하나하나가 각각 3바이트씩이다. 유니코드 환경에서는 옛 한글을 쓰기 위해서가 아니라면 조합형을 사용할 하등의 이유가 없는 것은 이 때문.

4. 문서에의 UTF-8


UTF-8은 엄밀히 따지면 유니코드의 데이터를 전송하기 위한 규격이지 문자 코드가 아니다. UTF 자체가 유니코드 전송 형식(Unicode Transfer Format)이라는 뜻이다. 하지만 대부분의 문자 코드가 전송 규격으로서의 의미를 가지고 있기 때문에 문자 코드로 유용을 하고 있는 것 뿐이다. 같은 의미로 UTF-16도 전송 규격이지만 이 규격이 실제 유니코드의 BMP0과 완전히 일치한다. 따라서 MS 계열 프레임워크에서 네이티브 언어(C/C++ 등)를 이용해 비 유니코드의 멀티바이트 캐릭터를 UTF-8 형식으로 변환하기 위해서는 와이드바이트 형식의 완전 2바이트 유니코드로 변환한 다음 다시 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의 존재 자체가 의미가 없기 때문이다. 그런데 비주얼 스튜디오는 상황이 좀 달라서, 소스 코드에 하드코딩된 유니코드 문자열이 있는 경우, BOM이 존재하지 않으면 ANSI 또는 시스템 코드 페이지로 소스 코드를 읽어들여 비 ASCII 문자열에 대해 오류가 나거나 코드 자체를 인식하지 못하는 경우가 존재한다. 그러므로 비주얼 스튜디오에서 문자열(특히 한글)을 정상적으로 출력하고 싶으면 소스 파일의 인코딩을 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를 사용하면 상당히 가벼워지지만, 라이브러리를 정적으로 링크할 경우[1] 라이센스 문제가 생길 수 있다.
윈도우 인사이더 프리뷰 17035(RS4)부터 "시스템 로캘 변경" 옵션에 "Beta: 세계 언어 지원을 위해 Unicode UTF-8 사용"이 추가되었다. # 이를 통해 윈도우에서 별도의 변환 과정 없이 UTF-8을 제한 없이 마음껏 사용할 수 있지만, 일부 프로그램은 ''와 같은 대치 문자를 띄우며 문자열 오류가 발생한다. 주로 국내 금융권 보안 프로그램, 또는 유니코드와 특정 인코딩을 섞어서 사용하는 프로그램에서 이러한 문제가 발생하는 것으로 보이며, 이에 대한 예로 와콤 타블렛 드라이버가 있다. 이를 제외한 오늘날의 대다수 프로그램들은 유니코드를 잘 지원하므로 사용상의 큰 문제는 없다. Microsoft PowerPoint는 이 옵션을 활성화했을 경우 새 페이지를 생성했을 때 기본적으로 들어가는 텍스트가 꺠져서 나오는 오류가 있긴 하지만, 지우고 다시 쓰면 되므로 커다란 문제점은 없다고 봐도 좋다.
윈도우 10 19H1 빌드의 메모장에서 BOM 없는 UTF-8이 기본 인코딩으로 변경되었으며, 저장 시 BOM을 붙일지 선택할 수 있게 변경되었다. 다만 BOM 없는 UTF-8 문서 자체는 기존 메모장(윈도우 XP 이상)에서도 잘만 읽어낸다.
C++11의 기능을 사용할 경우 유니코드 자료형을 사용할 수 있다. 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(RS4)부터 콘솔의 코드 페이지를 65001로 설정하는 함수를 통해 가능해졌다. 단, 입력과 출력만 UTF-8로 변경될 뿐, C++ 표준 템플릿 라이브러리의 (
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 부분이 인코딩 선언이다.[2] 어떤 웹 페이지에는 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용 특수 기호는 치환될 때도, 치환되지 않을 때도 있다.[3] 주로 치환되는 문자들을 나열하자면 다음과 같다.
  • 공백(space): %20[4]
  • !: %21
  • (: %28
  • ): %29
  • +: %2B
  • -: %2D
  • /: %2F
  • [: %5B
  • ]: %5D
  • _: %5F
인터넷 익스플로러구버전 Microsoft Edge[5]에서는 UTF-8로 저장된 파일을 다운로드할 때 EUC-KR로 읽어들여서 문자 깨짐이 발생한다. 하지만 크롬이나 파이어폭스에서는 멀쩡하게 나온다.

6. 관련 문서





[1] 하나의 실행 파일에 전부 포함하는 것이라고 보면 된다.[2] text/html 대신에 application/xhtml+xml 이 적힌 곳도 있고 아예 다른 게 있을 수도 있다.[3] 자바스크립트 기준으로 모두 치환하면 escape() 메서드를, URL용 : / ; ? 를 남기려면 encodeURI()나, encodeURIComponent() 메서드를 쓰며, 그 결과로 이렇게 된다.[4] +나 _로 인코딩되는 경우도 있다.[5] 2019년부터는 크롬 기반으로 변경되어 해당사항이 없다.