읽기 설정
UTF-8은 컴퓨터에서 텍스트를 인코딩하는 가장 일반적이고 널리 사용되는 시스템 중 하나입니다.00:00
당신이 이 영상을 보고 있는 웹페이지도 UTF-8로 인코딩되어 있을 가능성이 매우 높습니다.00:06
UTF-8에는 매우 흥미롭고 교묘하게 설계된 기능들이 많이 있지만, 이를 진정으로 이해하기 위해서는 컴퓨터 텍스트 인코딩의 역사를 조금 아는 것이 중요하다고 생각합니다.00:12
1940년대에 최초의 디지털 컴퓨터가 만들어졌을 때 대부분의 발전은 군대에 의해 이루어졌습니다. 주된 동기는 투사포 탄도 표와 같은 대규모 수치 계산을 가속화하는 것이었습니다.00:21
그 결과, 이러한 컴퓨터의 저장 공간은 숫자만 저장할 수 있었고, 수행할 수 있는 작업은 기본적인 산술 연산에 불과했습니다. 그러나 전쟁이 끝나고 컴퓨터 기술이 발전하면서 프로그래머들은 단순한 수치 계산을 넘어서는 다른 사용 사례를 탐구하기 시작했습니다.00:32
가장 초기이고 영향력이 큰 컴퓨터 활용 중 하나는 워드 프로세싱, 정부 기록 보관, 그리고 물론 의사소통 등을 위한 텍스트의 저장, 조작 및 출력이었습니다.00:49
컴퓨터 하드웨어가 내부에서 어떻게 작동하는지 잘 모른다면, 주장하여 숫자뿐만 아니라 텍스트도 메모리에 저장할 수 있게 하였고, 컴퓨터가 수행할 수 있는 작업이 단순한 산술 연산을 넘어 텍스트를 직접 처리할 수 있게 확장되었다고 생각하기 쉽습니다.01:05
하지만 놀랍게도, 그렇지 않습니다. 사실, 우리가 가지고 있는 가장 고급스러운 현대 컴퓨터조차도 여전히 숫자만 저장하고 연산합니다. 이는 그 당시의 프로그래머들이 순전히 수치적 기반 위에 텍스트 기능을 구축할 방법을 찾아냈어야 했다는 것을 의미합니다.01:21
공립 교육 시스템을 경험했다면, 아마도 사람들에게 숫자를 사용하여 문자를 대신하는 코드를 작성하라는 과제를 받은 적이 있을 것입니다. 이러한 코드는 알파벳의 각 문자에 고유한 숫자가 할당되어 메시지를 인코딩하고 디코딩할 수 있게 됩니다. 간단히 말하면, 이것이 컴퓨터에서 실행되는 방식입니다. '안녕하세요'와 같은 메시지를 컴퓨터 메모리에 저장하려면 먼저 '8, 5, 12, 12, 15'와 같은 형식으로 변환해야 합니다.01:39
100명에게 1부터 시작하여 영어 알파벳 각 문자에 숫자를 할당하라고 요청하면, 모두가 똑같이 A를 1, Z를 26으로 지정할 가능성이 높습니다. 하지만 초기 프로그래머들이 표현하고자 했던 대상은 영어 문자만이 아니었습니다. 더 많은 구두점도 포함해야 했습니다.02:11
만약 동일한 100명에게 알파벳 문자와 20개의 다른 구두점 기호에 숫자를 할당하라고 한다면, 구두점의 배열 방식에는 큰 차이가 있을 것입니다. 어떤 사람은 느낌표를 27로 지정할 수도 있고, 어떤 사람은 마침표나 콤마를 선택할 수도 있으며, 0에서 9까지의 숫자를 문자 뒤에 배치할 수도 있습니다.02:42
그리고 소문자뿐만 아니라 대문자까지 별도로 인코딩해야 한다고 상상해 보십시오. 마지막으로 수평 탭, 줄 바꾸기, 문서 끝 등 서식이나 인쇄용의 보이지 않는 문자를 추가한다면, 이 시점에서 100명에게 다시 묻는다면 아마 100개의 다른 배열을 가지게 될 것입니다. 이로 인해 1950년대 초기 텍스트 인코딩이 설계되었을 때 서로 다른 제조사의 기계에서 텍스트가 인코딩된 것은 디코딩되지 않는 일이 발생했습니다. 이 문제를 해결하기 위해 1963년에 미국 표준 협회는 지금의 ASCII 표준을 출판했습니다.03:06
ASCII는 각 문자를 인코딩하기 위해 7비트를 사용하며, 이것은 고정 폭 인코딩이라고 불립니다. 즉, 모든 ASCII 문자는 정확히 7비트입니다. 7비트는 128개의 다른 코드를 만들어 냅니다. 이는 대소문자 영어 알파벳뿐만 아니라 32개의 제어 코드와 현대 키보드에서 일반적으로 볼 수 있는 기호를 인코딩하기에 충분합니다.03:51
하위 수준의 컴퓨팅 개념에 조금 더 익숙한 사람들에게는 7비트 인코딩의 개념이 다소 이상하게 다가올 수 있습니다. 대부분의 메모리 관련 개념은 2의 거듭제곱으로 이루어져 있으며, 현대 컴퓨터에서 메모리의 가장 작은 주소 단위는 8비트인 바이트입니다. 하지만 1963년에는 고려해야 할 요인들이 많았습니다.04:26
네트워킹은 굉장히 느렸기 때문에 7비트 텍스트를 8비트보다 14% 더 빠르게 전송할 수 있다면 큰 차이를 만들었습니다. 그리고 당시 사용했던 테이프처럼 빠르지만 신뢰할 수 없는 저장 매체에서는 8비트를 패리티 비트로 사용하여 데이터 오류를 감지할 수 있었습니다. 이는 당시에는 꽤 자주 발생했습니다.04:48
제가 이 모든 것을 설명하는 이유는 7비트 형식을 ASCII로 결정한 것이 장기적으로 엄청난 예기치 않은 영향을 미쳤기 때문입니다. 잠시 후에 그 내용을 다루겠습니다.05:13
그래서 ASCII는 여러 차례 개정되어 널리 채택된 표준 텍스트 인코딩이 되어 컴퓨터 간의 상호 운용성을 크게 개선했습니다. 하지만 40년대와 50년대처럼 이후 몇 십 년간 컴퓨터 하드웨어 혁신이 계속되었으며 컴퓨터가 점점 더 널리 보편화되었습니다.05:25
1980년대로 빠르게 넘어가면서 컴퓨터는 비영어권 국가에서도 점점 인기를 끌게 되었습니다. 영어는 알파벳에 26개의 문자, 대문자와 소문자를 포함하면 52개밖에 없지만, 중국어나 일본어 같은 다른 언어는 일상적인 사용에서 수만 개의 고유한 문자를 가지고 있습니다.05:42
이 새로운 문자들을 인코딩하기 위한 경쟁적이고 호환되지 않는 표준의 폭발을 방지하기 위해, 1980년대 후반에는 여러 영향력 있는 회사의 구성원이 참여한 작업 그룹이 유니코드라는 표준의 초안을 발표했습니다.06:01
유니코드 표준의 목표는 모든 시각 문자를 각기 다른 숫자로 할당하여, ASCII처럼 보편적으로 합의된 표준을 갖는 것이었습니다. 이는 명백히 좋은 아이디어였지만, 이 시점에서 모든 문자에 고유한 숫자를 지정한 것에 불과합니다. 우리는 여전히 이 숫자를 이진수로 인코딩하는 방법을 알아내야 합니다. 그리고 여기서 문제가 시작됩니다.06:17
유니코드 표준에서 제시된 수만 개의 문자는 ASCII의 고정된 7비트로는 표현할 수 없습니다. 그래서 프로그래머는 딜레마에 직면하게 됩니다.06:48
각국과 각 언어가 서로 호환되지 않는 다양한 텍스트 인코딩을 사용하는 것을 인정하거나, 유니코드 표준에 정의된 모든 코드 포인트를 나타낼 수 있는 7비트 이상의 텍스트 인코딩을 개발해야 합니다.07:02
이것은 표면적으로는 그리 어려운 결정처럼 보이지 않을 수 있습니다. 더 많은 언어를 지원하려면 더 많은 비트가 필요하다는 것은 분명하기 때문입니다. 하지만 만약 우리가 새로운 표준 텍스트 인코딩을 채택한다고 동의하더라도, 기존의 ASCII에 맞게 구축된 수많은 이전 소프트웨어가 이러한 변화로 인해 모두 작동하지 않게 될 것입니다.07:18
시각적으로 이러한 원리를 이해하려면, 워드 프로세싱 소프트웨어가 각 코드 포인트를 8비트로 된 하나의 바이트로 표시할 것으로 기대한다고 상상해 보세요. 만약 우리가 인코딩을 각 코드 포인트에 16비트 또는 2바이트를 사용하는 것으로 바꾸면, 비록 문서가 ASCII 문자 집합만 사용했더라도, 이를 16비트 형식으로 인코딩하고 구식 8비트 워드 프로세서에서 읽으려 하면, 여전히 각 바이트를 개별 코드 포인트로 해석하려 하기 때문에 결과적으로 쓰레기 같은 결과가 나타날 것입니다.07:40
그리고 그뿐만 아니라, 그 시점까지 ASCII로 작성되고 저장된 모든 문서는 이 새로운 형식으로 변환되기 전까지는 새로운 소프트웨어에서 읽을 수 없을 것이었습니다. 만약 그렇게 되면, 디스크와 메모리에서 두 배의 크기가 될 것입니다. 왜냐하면 이제는 코드 포인트를 저장하기 위해 한 바이트 대신 두 바이트를 사용하기 때문입니다.08:12
우리는 이러한 변화를 하위 호환 불가능이라고 부릅니다. 새로운 소프트웨어는 이전 문서와 호환되지 않으며, 새로운 문서는 이전 소프트웨어와 호환되지 않습니다. 그러나 이러한 단점에도 불구하고, 하드웨어 및 소프트웨어 제조업체들은 이것을 가치 있는 거래로 간주하고 16비트 유선 텍스트 인코딩을 채택했습니다. 이것은 ASCII와 호환되지 않았으며, 실제로 오늘날에도 여전히 약간 다른 형식인 UTF-16이라는 이름으로 사용하고 있습니다.08:32
그러나 하위 호환이 불가능한 UTF-16과 그 전신은 많은 경우 실용적인 옵션으로 보이지 않았습니다. 이 시점에서 이메일 사용이 점점 더 확산되고 있었고, 일반적으로 SMTP로 불리는 간단한 메일 전송 프로토콜은 이메일 본문이 ASCII로 인코딩되어야 한다고 규정하고 있었습니다.08:54
그래서 국제 표준화 기구 ISO, 애플, IBM, 제록스를 포함한 여러 조직들이 ASCII를 확장할 하위 호환 방법을 개발했습니다. 그리고 실제로 그들 중 몇몇은 동시에 동일한 놀라운 아이디어에 도달했습니다. ASCII는 7비트만 사용한다고 제가 상기시켰다는 것을 기억하세요? 당시 대부분의 컴퓨터는 바이트 주소 지정 가능하여, 8비트 바이트가 컴퓨터가 사용할 수 있는 가장 작은 정보 단위라는 것을 뜻합니다.09:11
그래서 비록 ASCII가 7비트 인코딩일지라도, 디스크와 메모리에서 거의 항상 한 바이트 또는 코드 포인트당 8비트로 저장되고, 가장 높은 비트, 즉 여덟 번째 비트는 항상 0으로 설정되어 있습니다. 따라서 이 가장 높은 비트를 실제로 사용하면서 기존의 ASCII 인코딩과 충돌하지 않을 수 있습니다.09:36
그러나 7비트에서 8비트로 간다고 해서 128개의 가능한 코드 포인트만 추가되는 것은 초기적인 해결책입니다. 진정으로 영리한 아이디어는 가장 높은 비트를 사용하여 현재 코드 포인트가 실제로 8비트 이상이라는 것을 나타내는 것입니다. 즉, ASCII를 고정 폭 인코딩에서 가변 폭 인코딩으로 변환하는 것입니다. 이 아이디어는 모든 기존 ASCII 문자를 그대로 두는 것입니다.10:10
그렇게 하면 이전에 ASCII로 인코딩된 모든 텍스트가 이 새로운 형식에서 완전히 유효해집니다. 하지만 새로운 디코더가 가장 높은 비트가 1로 설정되어 있으면, 다중 바이트로 다음 코드 포인트를 인코딩해야 합니다. 예를 들어 4바이트를 사용할 경우 총 2^32, 즉 43억 개의 가능한 시퀀스를 제공하게 됩니다. 이것이 완벽한 해결책처럼 들리지만, 초기적인 접근에서 여러 가지 숨겨진 문제가 있습니다. 만약 앞으로 나아가면, 오래된 ASCII 텍스트 파일과 이메일은 이 새로운 가변 폭 디코더로 잘 작동할 것입니다.10:41
특정 함수에 필요한 특별한 코드 포인트들, 예를 들어 새 줄이나 널 종결자 같은 것들이 문자열의 끝을 나타내는데 사용되고, 이러한 것들이 멀티바이트 코드 포인트의 추가 바이트에 나타나면 예상치 못한 위험한 결과를 초래할 수 있습니다.12:44
즉, 지금까지의 인코딩은 뒤로 호환 가능하다는 것입니다. 새로운 디코더가 기존의 ASCII 데이터를 처리할 수 있지만, 기존의 ASCII 디코더는 새로운 데이터를 처리할 수 없습니다.12:58
그래서 이 문제를 해결하기 위해 여러 논의가 있었고, 1992년에 Unix System Laboratories의 Dave Prosser가 단순한 해결책을 제시했습니다.13:10
멀티바이트 시퀀스에서는 모든 바이트의 최고 비트가 1로 설정되어야 한다는 규칙을 만들어, 유효한 ASCII 문자로 혼동되지 않게 합니다.13:19
이로 인해 멀티바이트 코드 포인트에서는 바이트당 하나의 범위 비트를 잃게 되어 4바이트 시퀀스에서는 2의 28제곱의 가능성을 가지게 됩니다. 여전히 상당히 많은 2억 6천 8백만 가지입니다.13:30
이 새로운 인코딩은 매우 좋아 보이기 시작하지만 중요한 한 가지 한계가 있습니다. 이 한계는 단순한 가변 폭 인코딩의 고전적인 함정입니다. ASCII로 돌아가 보면 매우 흥미로운 속성들이 있는데, 종종 간과됩니다.13:40
모든 ASCII 코드 포인트는 동일한 폭을 가지고 있으며, 이 경우에는 현대에는 1바이트입니다. 인코딩의 형식은 모든 문자가 메모리나 디스크 상에 순차적으로 배치된다는 것입니다.13:53
컴퓨터 프로그래밍에서 모든 인코딩된 값이 동일한 폭으로 서로 인접하여 배열된 시퀀스를 배열이라고 부릅니다. 배열은 간단하지만 매우 강력한 속성을 가지고 있습니다.14:10
모든 요소가 동일한 폭이기 때문에 특정 인덱스에서 요소를 찾기가 매우 쉽습니다. 예를 들어 인덱스 7에서 요소를 찾는 것은 배열 요소의 고정 폭을 인덱스와 곱하는 것만으로 메모리 주소를 7바이트 이동해서 알 수 있는 것입니다.14:22
이것이 명확해 보일지 모르지만, 이 구분은 정말 중요합니다. 특정 인덱스에서 문자를 찾는 능력은 요소들이 동일한 폭이라는 사실에 달려 있습니다.14:41
만약 제가 이제 요소가 1바이트가 아닌 1바이트에서 4바이트 사이의 크기를 가지고 있다고 말하면, 인덱스 7에서 요소를 어떻게 찾겠습니까? 불행하게도 유일한 방법은 처음부터 모든 인코딩된 텍스트를 하나씩 셉니다.14:54
재미있게도 여기에는 연결 리스트의 특성과 강력한 평행이 있습니다. 그것이 제가 언급했던 주요 한계라고 생각할 수 있지만, 놀랍게도 큰 문제가 아닙니다.15:13
UTF-8 텍스트 파일에서 50,000번째 문자를 찾는 것은 사실 그다지 흔하지 않은 작업입니다. 만약 그런 작업을 원한다 해도, 한 번 파일을 읽고 오프셋 테이블을 작성한 후 빠르게 검색할 수 있습니다.15:25
실제 문제는 텍스트를 디코드하는 능력이 전적으로 첫 번째 바이트를 아는 것에 전적으로 달려 있다는 것입니다. 첫 번째 바이트가 없다면 두 번째 바이트가 실제로 무엇을 의미하는지 해석할 수 없습니다.15:40
정확히 말하자면 첫 비트가 0이면 단일 바이트 ASCII 문자라는 것을 알 수 있습니다. 그러나 첫 비트가 1이면 이것이 멀티바이트 시퀀스의 첫 번째, 두 번째, 또는 네 번째 바이트인지 어떻게 알 수 있습니까?15:52
이 제한은 멀티바이트 코드 포인트만 있는 파일, 예를 들어 중국어 파일에 모든 바이트 손실 시 전체 파일을 잃게 됩니다. 어떤 바이트가 문자 시작인지 중간인지 더 이상 알 수 없게 됩니다.16:12
생각해보면, 네, 이건 나쁜 일이지만, 바이트 손실 같은 것은 드문 경우 아닌가요? 분명히 그렇겠죠?16:22
그렇지만 실제로는 그렇지 않습니다. 인터넷을 통해 텍스트 스트림을 임의의 지점에서 받기 시작한다고 가정하면, 우리가 코드 포인트의 시작인지 중간인지 모른다면 컴퓨터는 명확하게 디코딩할 수 없게 됩니다.16:27
이런 인코딩은 동기화가 필요하다고 말할 수 있습니다. 이 방식으로 인코딩된 텍스트 본문의 일부를 받을 때 서버는 당신이 받는 첫 번째 바이트가 코드 포인트의 첫 번째 바이트와 동기화되어 있도록 해야 합니다. 이는 구현을 훨씬 더 복잡하게 하고 오류가 발생하기 쉽습니다.16:44
다행히도 이런 이야기에는 항상 영웅이 있고, 특히 이 문제는 벨 연구소의 켄 톰슨이 뉴저지의 한 다이너에서 몇 시간 만에 해결했습니다. 컴퓨터 역사에 대해 많이 읽어보지 않으셨다면, 제가 스포일러를 드리자면, 항상 켄 톰슨입니다.17:00
이 이야기는 로브 파이크가 직접 전해준 내용으로 설명란에 링크를 걸어놓겠습니다. 하지만 제가 여기서 더 다루고 싶은 것은 기술적인 세부사항입니다. 켄 톰슨이 이루려고 했던 것은 가변 폭 인코딩의 자기 동기화라는 특성이었습니다. 이는 인코딩된 데이터의 임의의 지점에 들어가도 전체를 처음부터 디코딩하지 않고도 요소의 가장 가까운 경계를 찾을 수 있는 방법을 제공합니다. 이를 이해하려면 멀티바이트 코드 포인트의 여러 바이트를 어떻게 지칭하는지를 정의해야 합니다. 멀티바이트 코드 포인트의 첫 번째 바이트는 일반적으로 선도 바이트라고 하고, 이후의 바이트는 연속 바이트라고 합니다.17:20
즉, 켄 톰슨이 해결해야 했던 문제는 선도 바이트를 명확하게 식별하는 것이었습니다. 데이브 프로서의 설계는 이미 1바이트 ASCII 문자에 대해 최상위 비트를 0으로 설정하여 고유하게 식별했습니다. 따라서 랜덤 바이트에 들어가서 최상위 비트가 0으로 설정되어 있으면, 이는 이미 동기화된 상태라는 것을 알 수 있습니다. 그래서 켄 톰슨의 문제는 멀티바이트 코드 포인트의 모호성을 해결하는 것으로 축소되었습니다.17:59
선도 바이트를 연속 바이트와 구분하려면 어떻게 해야 할까요? 재미있게도 켄은 거의 데이브 프로서와 같은 방식으로 대응했습니다. 켄 톰슨은 멀티바이트 코드 포인트의 모든 선도 바이트가 11로 시작하고, 연속 바이트는 10으로 시작하도록 결정했습니다. 최상위 비트는 코드 포인트가 단일 바이트 ASCII 문자인지 여부를 알려주고, 두 번째 최상위 비트는 선도 바이트인지 연속 바이트인지를 알려줍니다.18:59
파일을 바이트 배열로 처리하면 배열의 속성을 사용하여 바이트 측면에서 중간 지점으로 이동할 수 있으며, 현재 바이트의 최상위 비트가 0인지 확인할 수 있습니다. 그렇다면 이 바이트는 ASCII 코드 포인트로 이미 동기화된 상태입니다. 그렇지 않으면 멀티바이트 시퀀스에 있는 것이므로 이전 바이트로 이동하여 같은 작업을 반복합니다. 적절히 인코딩된 파일에서는 동기화 포인트를 찾기 위해 최대 3바이트만 앞으로 탐색하면 됩니다. 왜냐하면 가장 넓은 코드 포인트는 4바이트이기 때문입니다.19:47
가변 폭 인코딩을 통해 더 많은 코드 포인트를 지원하고, ASCII와의 완전한 호환성을 유지하며, 자기 동기화 속성을 갖추게 하는 세 가지 혁신이 표준화되어 지금 우리가 UTF-8이라고 부르는 방식으로 발전했습니다. 이는 브라우저와 인터넷에서 사실상의 텍스트 인코딩 방식이 되었습니다. 전체 웹 페이지의 99.9% 이상이 UTF-8 인코딩을 선언하고 있습니다. 또한, 자세히 설명하자면 UTF는 유니코드 변환 형식을 의미하며, 유니코드는 우리가 합의한 코드 포인트의 총집합 이름으로, 글쓰기 언어, 기호, 이모티콘 등을 포함합니다.20:04
8비트는 가장 작은 코드 포인트의 기본 크기를 나타냅니다. UTF-16과 대조적으로, 윈도우에서 주로 사용하는 UTF-16은 가장 작은 코드 포인트가 16비트이고, 심지어 UTF-32는 모든 코드 포인트에 대해 32비트를 사용합니다. 이 세 가지 UTF 인코딩은 모두 유니코드 컨소시엄에 의해 공식적으로 지원되고 정의됩니다.20:47
이들은 유니코드 표준에 정의된 모든 코드 포인트를 각각 표현할 수 있으며, 이를 달성하기 위해 다른 이진 표현을 사용합니다. 이 비디오를 보기 전에는 아마도 'UTF-32의 의미가 무엇일까?'라고 생각하셨을 것입니다. 모든 코드 포인트에 4바이트를 사용하는 것은 낭비처럼 보일 수 있습니다.21:12
하지만 이제는 UTF-32가 단순한 고정 폭 배열이기 때문에 프로그래머로서 구현하기 훨씬 더 간단하고 쉬울 것이라고 직관적으로 느낄 수 있을 것입니다. 따라서 가변 폭 코드 포인트나 동기화를 처리하기 위한 추가 기계가 필요 없습니다. 그래서 구현의 단순성이 더 많은 메모리와 저장 용량의 낭비적 특성과 맞바뀌는 것입니다.21:34
추상적으로 생각해 본다면, UTF-8은 UTF-32에 비해 일종의 압축 형태입니다.21:54
이제 UTF-8 인코딩의 개발 동기와 역사를 조금 더 이해하셨으니, 아직 논의하지 않은 인코딩의 몇 가지 특징을 자세히 살펴보겠습니다.22:01
먼저, 멀티바이트 코드 포인트의 바이트 수를 결정하는 방법을 설명하지 않았습니다. 이 위키백과 차트는 이진수와 16진수에 대한 이해도가 좋은 경우 훌륭한 시각화 도구입니다.22:13
하지만 많은 사람들이 이해하기 어려울 수 있으므로, 조금 더 명확하게 설명해 드리겠습니다.22:23
일반적으로, 바이트는 256개의 가능한 값을 나타낼 수 있는 데이터 단위입니다. 즉, 숫자 0에서 255까지입니다.22:30
우리의 10진수 시스템에서는 가장 큰 값인 255를 세 자리 수로 표현합니다: 일의 자리 5, 십의 자리 5, 백의 자리 2입니다.22:39
이진수, 즉 2진수에서는 바이트가 대신 8개의 이진 숫자로 표현됩니다. 이것이 바로 '비트'라는 단어의 약어입니다.22:51
그래서 이진수에서 255는 8개의 1로 표현됩니다. 이진수에서는 각 자릿수가 2의 거듭제곱입니다.22:59
1의 자리, 2의 자리, 4의 자리, 8의 자리, 16의 자리, 32의 자리, 64의 자리, 128의 자리 모두 1이 됩니다. 이를 모두 더하면 255가 됩니다.23:10
따라서 이는 같은 숫자를 표현하는 두 가지 방법일 뿐입니다. 이는 물론 16진수 또는 헥사데시멀로 이어집니다.23:24
마치 각 10진수 자릿수가 10개의 값을 나타낼 수 있고, 각 이진수 자릿수가 2개의 값을 나타낼 수 있는 것처럼, 각 16진수 자릿수는 16개의 값을 나타낼 수 있습니다. 0부터 9까지의 기호가 직접 사용되며 a부터 f는 10에서 15를 나타냅니다.23:31
이진수와 10진수처럼 열은 정확히 동일한 방식으로 기능합니다. 1의 자리에는 'f'가 있고, 이는 15개를 나타내며, 16의 자리에는 'f'가 있어 15 곱하기 16, 즉 240을 나타냅니다. 그래서 15에 240을 더하면 총 255가 됩니다.23:49
만약 저와 비슷하다면, 처음 16진수를 접했을 때 매우 직관적이지 않고 이해하기 어려웠습니다. 그런데 왜 처음부터 16진수를 사용하는 걸까요? 만약 단지 이진수로 숫자를 쓰는 것을 피하고 싶다면, 차라리 10진수를 사용하는 게 낫지 않을까요? 훨씬 이해하기 쉬운 방법 아닐까요?24:10
사실 이진 데이터를 16진수로 표현해야 하는 정말 좋은 이유가 있습니다. 단일 16진수 자릿수만 봐도 0에서 f까지 나타낼 수 있습니다.24:26
10진수로 동일한 표현은 0에서 15까지가 될 것입니다. 그리고 흥미로운 점은 여기서 0부터 15까지를 나타내기 위해 두 자리의 10진수를 필요로 하지만, 16진수 한 자리로는 충분하다는 것입니다.24:38
10진수를 사용하면 최대 99까지 표현할 수 있으며, 이는 더 많은 16진수를 필요로 합니다. 이렇듯 서로의 기수가 일치하지 않지만, 0부터 15까지의 이진 표현을 보면 흥미로운 점이 있을 수 있습니다. 15는 이진수 4자리가 필요하지만, 정확하게 4비트로 표현할 수 있는 가장 큰 수입니다. 즉, 하나의 16진수 자릿수는 4개의 이진수 자릿수와 정확히 일치합니다.24:54
수학에 익숙한 사람들에게는, 2의 4제곱이 16이라는 것을 알 것입니다. 2진수의 4자리는 16진수의 1자리에 해당합니다. 결과적으로 8비트 바이트는 정확히 두 자리의 16진수로 표현할 수 있습니다. 이는 이진수보다 훨씬 간결한 표기법이면서도 바이트의 경계를 정확하게 시각화할 수 있는 능력을 유지합니다.25:22
그러므로 모든 1바이트 ASCII 문자는 예를 들어 두 자리의 16진수 표현을 가지고 있습니다. 차트로 돌아가 보면, 이들은 모든 가능한 값을 나타내기 위해 이 시스템을 설정한 것을 볼 수 있습니다.25:39
한 바이트를 두 개의 16진수 자리로 표현하면 오른쪽 끝의 16진수 자릿수는 표에서 왼쪽에서 오른쪽으로 이동하고 위쪽 또는 왼쪽 끝의 16진수 자릿수는 위에서 아래로 이동합니다. 이를 이진수로 변환할 때, 상단 디짓이 8 이상인 모든 16진수 시퀀스는 이진 시퀀스에서 상위 비트가 1과 같으며 따라서 전체 첫 번째 절반은 상위 비트가 0인 ASCII 인코딩이고 두 번째 절반은 상위 비트가 1인 UTF-8 인코딩입니다.25:51
Ken Thompson이 연속 바이트가 이진수로 10으로 시작해야 한다고 결정했다는 것을 기억하시나요? 이는 이 전체 범위가 연속 바이트를 나타내는 데 사용된다는 것을 의미합니다. 이것은 UTF-8의 자체 동기화 특성의 비용을 시각화한 훌륭한 예입니다. 바이트의 4분의 1이 이 기계에 사용됩니다.26:19
그리고 이 하단 구역은 다중 바이트 코드 포인트의 선행 바이트를 인코딩하는 곳입니다. 이 차트에서 선행 바이트의 상위 16진수 디짓이 C 또는 D이면 2바이트 코드 포인트이고, E이면 3바이트 코드 포인트이며, F이면 4바이트 코드 포인트입니다. 여기서 C0과 C1 같은 특정 값과 F5 이후의 모든 시퀀스는 엄격히 유효하지 않으며 UTF-8로 디코딩될 수 없음을 주목하는 것이 중요합니다.26:47
표준은 실제로 유효하지 않은 인코딩의 모든 문자를 잘 알려진 유니코드 대체 문자로 교체할 것을 명시적으로 권장합니다. 이 문자는 도로 표지판에 있는 물음표와 약간 비슷하게 보이며 특수한 3바이트 시퀀스 EFBFBD를 가지고 있습니다. 이 문자는 주로 실행 파일이나 이미지 파일을 텍스트 편집기로 열 때 볼 수 있습니다.27:17
첫 번째 바이트를 디코딩한 후에는 얼마나 많은 추가 바이트가 오는지 알게 되고, 모든 추가 바이트는 연속 바이트로 인코딩되며 모든 바이트는 상위 두 비트가 10으로 설정되고 나머지 6비트는 실제 코드 포인트를 인코딩하는 데 사용됩니다. 하지만 아직 몇 가지 미해결된 질문이 남아 있습니다. 이러한 연속 바이트들이 최종 코드 포인트에 어떻게 기여하는지.27:42
그리고 왜 선행 바이트들이 총 길이를 2, 3, 또는 4로 나타내는 다양한 방법이 있는지에 대한 것입니다. 이는 실제로 매우 우아하고 간단한 시스템입니다. 2바이트 코드 포인트를 이진수로 인코딩하는 방법을 보면, 처음 세 비트가 110으로 보장되어 있으며, 이는 이 범위에 해당합니다. 3바이트 코드 포인트는 1110으로 시작하며, 이는 이 범위에 해당합니다. 4바이트 코드 포인트는 11110으로 시작합니다.28:22
어떤 비ASCII 코드 포인트든지 UTF-8에서 이진 표현의 선행 1의 수는 바이트 수에 해당합니다. 2바이트 코드 포인트에는 2개의 1, 3바이트에는 3개의 1, 4바이트에는 4개의 1이 있습니다. 이런 작은 디테일을 발견하는 것이 너무 좋습니다. 디자이너가 남겨둔 비밀 메시지를 발견하는 것 같은 느낌입니다.28:49
그래서 코드 포인트의 각 바이트의 처음 몇 비트는 길이와 선행 바이트인지 연속 바이트인지에 따라 고정됩니다. 그 밖에 UTF-8의 작동 방식은 인코딩 자체의 일부가 아닌 나머지 비트를 모두 하나의 큰 이진수로 합쳐 유니코드 코드 포인트를 만드는 것입니다.29:13
21비트의 값들은 약 210만 개의 코드 포인트를 다룰 수 있습니다. 여기서 흥미로운 점이 있는데, 만약 각 바이트의 남는 비트들을 연결해 만든 이진수 숫자가 코드 포인트와 직접 대응된다면, 일부 코드 포인트는 여러 가지 방법으로 표현이 가능하지 않을까요?29:27
예를 들어, 코드 포인트 2047은 이진수로 11이므로 2바이트, 3바이트 또는 4바이트로 표현할 수 있습니다.29:47
이것은 실제로 큰 문제입니다. 만약 두 개의 유니코드 문자열을 비교하여 동일한지 확인하려고 한다면, 가장 높은 성능의 방법은 원시 바이트 시퀀스를 서로 비교하는 것이지만, 동일한 코드 포인트를 인코딩하는 다른 바이트 시퀀스가 있을 수 있기 때문에 실제로 두 문자열을 먼저 UTF-8로 디코딩한 후 디코딩된 코드 포인트를 비교해야 합니다.29:56
두 파일의 해시를 비교하여 동일한지 확인하려고 한다면, 동일한 유니코드 텍스트를 포함한 두 파일이 서로 다른 해시를 생성할 수도 있습니다.30:18
이를 해결하기 위해 UTF-8 표준에서는 코드 포인트의 가장 짧은 표현만 실제로 사용해야 한다고 규정합니다. 따라서 0에서 127까지의 ASCII 범위를 2바이트 이상으로 표현할 수 없고, 2바이트 범위의 문자를 3바이트나 4바이트로 표현할 수 없습니다.30:28
요약하자면, 4바이트의 UTF-8로 총 2의 21제곱의 코드 포인트를 표현할 수 있는데, 이는 4바이트를 사용하므로 기대했던 2의 32제곱보다 상당히 적습니다. 그렇다고 해도 중앙 유니코드 표준은 실제로 110만 개의 코드 포인트만 정의하고 있으며, 현재까지 약 30만 개가 실제로 할당되었습니다.30:47
이는 엄청난 여유 공간을 남깁니다. 물론 우리가 수백만 개의 문자를 사용하는 외계 종족과 마주칠 때까지는 그렇겠지만, 그때쯤이면 아마 더 큰 문제가 있을 것입니다.31:05
이것이 사양 자체의 기술적 세부 사항의 끝입니다. 마무리로, 유니코드 코드 포인트 전체 범위에 걸쳐 다양한 문자와 기호가 실제로 어떻게 할당되는지 느낌을 주는 것이 좋을 것 같습니다.31:23
한 바이트로는 표준 ASCII 문자의 128개를, 두 바이트로는 총 2048개의 코드 포인트를 표현할 수 있으며, 이는 작은 알파벳을 사용하는 대부분의 인류 언어와 몇 가지 공통 기호를 포함합니다.31:37
3바이트는 65,536개의 코드 포인트를 제공하며 주로 중국어, 일본어, 한국어 등의 동아시아 문자 체계를 표현하는 데 사용됩니다. 또한 더 많은 수학 기호와 점자 알파벳이 포함됩니다.31:51
4바이트는 210만 개의 코드 포인트를 제공하며, 이는 현대 이모지가 대부분 있는 곳입니다. 현재 UTF-8은 최대 4바이트만 지원하지만, 두 개의 개별 코드 포인트를 연결하는 데 사용되는 3바이트 문자인 제로 폭 조인러가 있습니다.32:22
이모지 가족은 단일 4바이트 코드 포인트가 아니라 세 개의 제로 폭 조인러로 연결된 네 개의 4바이트 이모지로 구성됩니다. 그래핤 클러스터는 이처럼 함께 결합하여 하나의 시각적 문자로 렌더링되는 코드 포인트 그룹을 나타냅니다.32:44
이론적으로는 킬로바이트 이상의 크기까지 임의의 크기의 그래핤 클러스터를 생성할 수도 있으므로 UTF-8 파서를 구현할 때 지원할 최대 그래핤 클러스터 크기를 선택하는 것이 좋습니다.33:14
유니코드에서 코드 포인트로 배열된 방법에 대해 배운 적이 없다면, 한국어 문자 체계가 어떤 방식으로 작동하는지 이해하기 어려우실 수 있습니다. 겉으로는 수많은 문자로 이루어진 중국어나 일본어와 비슷해 보일 수 있지만, 놀랍게도 영어와 훨씬 더 비슷합니다.33:42
각 문자는 음절로 불리며, 자음과 모음으로 구성되어 있으며, 작은 간단한 알파벳에서 가져와 다양한 규칙에 따라 결합됩니다. 실제로 핵심 자음은 14개, 모음은 10개로 24개가 있는데, 이는 영어의 26개보다 적습니다.33:57
그 결과, 놀랍게도 한글은 유니코드에서 11,184개의 코드 포인트를 차지합니다. 하지만 알파벳에 24개만 필요하다면 그 이유는 뭘까요?34:08
한국어 음절은 최대 다섯 개의 부분으로 구성될 수 있어서, 만약 제로 폭 조인어를 사용해 큰 음절로 결합한다면 한 음절에 27바이트가 필요합니다. 이로 인해 한글 인코딩 비용은 전용 인코딩과 비교했을 때 감당할 수 없을 정도로 비싸질 것입니다.34:22
그 결과, 한글은 처음부터 유니코드 채택에 대한 설득이 어려웠을 것입니다. 이미 UTF-8에서 3바이트 범위에 할당된 것으로 결정되어 있어 훨씬 더 큰 공간을 활용할 수 있었고, 결과적으로 매우 영리한 아이디어가 탄생했습니다.34:39
첫 번째 부분은 꽤 명확합니다. 한글의 각 자음과 모음뿐만 아니라 각 완성된 음절에도 고유한 유니코드 코드 포인트가 있습니다. 따라서 11,000개 이상의 모든 조합이 단 3바이트로 표현 가능합니다.34:58
그러나 여기에는 약간의 미묘함이 있습니다. 한글은 실제로 매일 사용되는 실재의 문자 체계이기 때문에, 가장 일반적인 작업 중 하나는 휴대폰이나 컴퓨터에서 키보드를 사용하여 한글을 입력하는 것입니다.35:18
영어 키보드와 마찬가지로, 한국어 키보드는 각 자음과 모음에 매핑된 키가 있으며, 음절을 입력하려면 예를 들어 자음, 모음, 자음을 차례로 입력하여 최종 음절을 구성합니다.35:30
그리고 실수할 경우 백스페이스를 눌러 음절의 일부를 삭제할 수 있습니다. 하지만 최종 음절 문자의 코드 포인트가 무작위로 할당되었다면, 자음과 모음으로 음절을 구성하는 과정은 상당한 계산적 도전이 되었을 것입니다.35:42
사실상 가능한 모든 조합의 순서를 인코딩하고 코드 포인트로 매핑하는 거대한 테이블 세트를 구현해야 했을 것입니다. 이를 쉽게 하기 위해, 한글 음절 블록에는 매우 영리한 내부 규칙이 있습니다.35:57
자음과 모음의 코드 포인트로부터 음절의 코드 포인트를 유도할 수 있는 간단한 수학적 공식이 있습니다.36:13
여기 있는 이 음절은 전통적으로 K-I-M 또는 G-I-M으로 로마자로 표기됩니다. 이는 김치의 첫 번째 음절이자 가장 일반적인 한국 성씨인 김입니다.36:23
이 공식을 사용하여 이를 분해해 봅시다. 첫 번째 자음의 값을 첫 번째 테이블에서 가져와 588을 곱합니다. 다음으로 중간 음절인 모음 E를 가져와 그 값을 찾아 28을 곱하고 현재 총합에 더합니다. 그런 다음 마지막 자음 M의 값을 이 테이블에서 추가한 다음, 유니코드 한글 음절 블록의 시작인 44,032를 최종적으로 더합니다.36:33
그렇게 하면 총 44,608이 되며, 이를 16진수로 변환하면 AE40이 됩니다. U+AE40을 찾아보면 전체 음절 'Kim'에 대한 유니코드 문자를 확인할 수 있습니다. 꽤 멋지지 않나요?37:00
작은 여담으로, 몇 년 전 한글 음절을 분해하고 결합하는 것을 주요 기계니즘으로 사용하는 작은 퍼즐 게임을 만들었습니다. 관심이 있으시면 비디오 설명에 링크를 걸어 두겠습니다.37:16
물론 한국어만이 내부 구현이 뛰어난 유일한 언어는 아닙니다. 유니코드 표준에는 더 많은 비밀들이 숨겨져 있습니다.37:27
이 영상이 유니코드와 특히 UTF-8에 관한 주제를 조금 이해하는 데 도움이 되었기를 바랍니다.37:35
시청해 주셔서 감사합니다.37:40
AI Summary
이 자료는 UTF-8 인코딩 방식과 한글 유니코드 인코딩의 효율성에 대해 설명합니다. UTF-8은 가변 길이 인코딩 방식으로 다양한 문자를 지원하며, 자체 동기화 기능을 제공하지만 공간 효율성이 떨어질 수 있다는 단점도 있습니다. 특히 한글 유니코드 인코딩은 자음과 모음을 조합하여 음절을 구성하는 방식을 사용하며, 음절 코드 포인트 할당의 어려움을 극복하기 위해 수학적 공식을 활용하여 계산 부담을 줄입니다. 이를 통해 11,000개 이상의 가능한 한글 조합을 단 3바이트로 표현할 수 있습니다.
Key Highlights
- •UTF-8은 가변 길이 인코딩 방식으로 1~4바이트를 사용하여 다양한 문자를 표현합니다.
- •UTF-8은 자체 동기화 기능을 통해 데이터 손상 시 오류를 감지하고 복구하는 데 도움을 줍니다.
- •한글 유니코드 인코딩은 자음과 모음의 조합을 통해 음절을 구성합니다.
- •음절 코드 포인트는 수학적 공식을 통해 효율적으로 계산됩니다.
- •한글 유니코드 인코딩은 3바이트로 11,000개 이상의 가능한 조합을 표현할 수 있습니다.
Related Videos

UTF-8: The Internet's current favorite text encoding scheme

UTF-8, Explained Simply

ASCII, Unicode, UTF-8: Explained Simply

Characters, Symbols and the Unicode Miracle - Computerphile

Unicode, in friendly terms: ASCII, UTF-8, code points, character encodings, and more

UTF-8 characters | #HTMLBasics #WebDevelopment #HTMLTutorials #LearnHTML #CodingForBeginners

How Computers Store Text - ASCII, Unicode, UTF-8, UTF-16, and UTF-32
![[볼륨주의] 문자 인코딩, 유니코드, UTF-8이 뭔가요?](https://i.ytimg.com/vi/1jo6q4dihoU/mqdefault.jpg)
[볼륨주의] 문자 인코딩, 유니코드, UTF-8이 뭔가요?

What is UTF-8 character encoding and why is it needed?

If You Can't Explain UTF 8 vs Unicode, Watch This

What are UTF-8 and UTF-16? Working with Unicode encodings

いまさら聞けない文字コード。UTF-8って何?(字幕あり)

Ep 020: Unicode Code Points and UTF-8 Encoding

문자 인코딩 초간단 개념 정리 (UTF-8, 아스키, 유니코드...)

How to Enable UTF-8 (Beta) in Windows 10/11 | Fix Unicode Text Problems?

Strings, Default Charsets and UTF-8 #java #shorts #coding #airhacks

UTF-8って何?Unicodeのコードポイントって何?どういう関係?

UTF-8 とアスキーがわからない文系のアホ上司 20210404【1 2倍速】【ひろゆき】

Unicode Encoding! UTF-32, UCS-2, UTF-16, & UTF-8!

개발자라면 꼭 알아야 할 ASCII부터 UTF-8까지

UTF 8 -- Daniel Morsing

UTF-8 - 文字コード2 #応用情報技術者試験 #shorts

Ep 021: UTF-8 Encoding Examples

【誰でもわかる】UTF 8とは
