UTF-8이 인코딩에서 여러 비트를 낭비하는 이유


17

Wikipedia 기사 에 따르면 UTF-8의 형식은 다음과 같습니다.

첫 번째 코드 마지막 코드 바이트 바이트 1 바이트 2 바이트 3 바이트 4
사용 된 포인트
U + 0000 U + 007F 1 0xxxxxxx
U + 0080 U + 07FF 2110xxxxx 10xxxxxx
U + 0800 U + FFFF 3 1110xxxx 10xxxxxx 10xxxxxx
U + 10000 U + 1FFFFF 4 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
x는이 비트가 코드 포인트를 선택하는 데 사용됨을 의미합니다.

이렇게하면 각 연속 바이트에서 2 비트와 첫 번째 바이트에서 1 비트가 낭비됩니다. UTF-8이 다음과 같이 인코딩되지 않은 이유는 무엇입니까?

첫 번째 코드 마지막 코드 바이트 바이트 1 바이트 2 바이트 3
사용 된 포인트
U + 0000 U + 007F 1 0xxxxxxx
U + 0080 U + 3FFF 2 10xxxxxx xxxxxxxx
U + 0800 U + 1FFFFF 3110xxxxx xxxxxxxx xxxxxxxx

코드 포인트가 기본 다국어 평면을 벗어나거나 코드 포인트가 [U + 800, U + 3FFF] 범위에있는 경우 1 바이트를 저장합니다.

UTF-8이 왜 더 효율적인 방식으로 인코딩되지 않습니까?


3
cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt 제안 된 인코딩은 원본 FSS / UTF 제안과 유사합니다. Ken Thompson과 Rob Pike는 자체 동기화 속성을 원했습니다.
ninjalj

4
또한 인코딩이 ASCII 코드 값이 ASCII가 아닌 문자 표현의 일부에 나타나지 않는다고 보장하지는 않습니다. FSS / UTF 및 UTF-8은 레거시 프로그램 (예 : ASCII NUL 및 슬래시 (경로 구분 기호)을 구분 기호로 사용하는 프로그램)에서 작동하도록 설계되었습니다.
ninjalj

답변:


26

다중 바이트 시퀀스 중간에있을 때이를 감지 할 수 있습니다. UTF-8 데이터를 볼 때, 당신은 당신이 보는 경우 알고 10xxxxxx, 당신은 멀티 바이트 문자의 중간에 있는지, 그리고 당신이 중 하나가 표시 될 때까지 스트림에 백업해야합니다 0xxxxxx11xxxxxx. 체계를 사용하면 바이트 2 또는 3은 쉽게 0xxxxxxx또는 같은 패터로 끝날 수 있습니다11xxxxxx

또한 저장되는 양은 인코딩하는 문자열 데이터의 종류에 따라 달라집니다. 대부분의 텍스트, 심지어 아시아 텍스트의 경우 일반 텍스트가있는 4 바이트 문자는 거의 볼 수 없습니다. 또한 텍스트가 어떻게 보일지에 대한 사람들의 순진한 추정은 종종 틀립니다. 일본어, 중국어 및 한국어 문자열을 포함하여 UTF-8로 현지화 된 텍스트가 있지만 실제로 대부분의 공간을 차지하는 것은 러시아어입니다. (아시아 문자열에는 종종 이름과 문장 부호 등으로 로마 문자가 산재되어 있기 때문에 평균 중국어 단어는 1 ~ 3 자이고 평균 러시아어 단어는 더 많기 때문에 더 많습니다.)


그러나 나에게 구성표를 사용하면 문자를 구걸하는 것으로 알려진 위치에서 시작하면 문자에 몇 바이트가 있는지 말하고 다음 문자를 구걸 할 수 있습니다.
qbt937

11
확실한. 체계가 정보 밀도가 높지만 UTF-8이 제공하는 중요한 기능은 없습니다. 일반적으로 사람들은 안전성을 선호하므로 UTF-8이 가능합니다. 또한 실제로 체계가 실제로 더 효율적임을 입증하기 위해 실제 텍스트를 사용하여 통계를 제공하려고합니다. 대부분의 실제 텍스트에서 체계가 매우 사소한 금액을 절약하므로 절약 할 가치가 없다는 것을 알 수 있습니다.
로봇

3
또 다른 중요한 특성 : 0 코드 포인트가 포함되어 있지 않으면 문자열에 0이 포함되지 않은 것입니다.
중복 제거기

태국어 스크립트의 경우 인쇄 된 문자 당 4 바이트를 허용해야합니다. 그들은 파티에 늦게 도착했을뿐만 아니라 높은 코드 그룹을 얻었습니다. 인쇄시 단일 문자처럼 보이는 많은 것들은 실제로 세 가지 다른 유니 코드 문자로 구성됩니다.
James Anderson

@ qbt937 : 체계를 사용하면 한 문자열에 다른 문자열이 포함되어 있는지 확인하기 위해 어떻게 빠르게 스캔합니까?
supercat

6

공식적인 방법은 디코더가 튜플의 중간에있을 때 알리고 바이트가 0또는로 시작될 때까지 바이트를 건너 뛰거나 뒤로 이동하는 것을 알고 있습니다 11. 이것은 단일 바이트가 손상 될 때 가비지 값을 방지합니다.


3

짧은 대답, 당신의 제안은 첫 바이트와 연속 바이트를 구별하지 않습니다.

첫 번째 바이트의 상단에있는 비트 패턴은 실제 문자가 몇 바이트 나 작성되는지 알려줍니다. 이러한 패턴은 문자열을 구문 분석하는 동안 오류 인식도 제공합니다. 문자의 (겉보기) 첫 바이트를 읽고 10xxxxxx를 얻는다면 동기화되지 않은 것입니다.


2

언급되지 않은 것은 올바른 코드 포인트 시퀀스와 코드 포인트의 첫 번째 바이트를 가리키는 포인터가 UTF-8을 사용하면 첫 번째 바이트에 대한 포인터를 매우 쉽게 찾을 수 있다는 것입니다 이전 코드 포인트의 (01xx xxxx로 시작하는 모든 바이트 건너 뛰기) 인코딩을 사용하면 문자열의 시작 부분까지 모든 바이트를 검사하지 않으면 불가능합니다.

(2n + 2) 바이트의 시퀀스를 고려하십시오

0xxxxxxx
n times (10xxxxxx, 10xxxxxx)
0xxxxxxx

n times (10xxxxxx, 10xxxxxx)
(10xxxxxx, 0xxxxxxx)

이 시퀀스 다음에 첫 번째 코드 포인트의 첫 번째 바이트에 대한 포인터가있는 경우 모든 코드를 검사 하여 마지막 코드 포인트가 0xxxxxxx인지 (10xxxxxx, 0xxxxxxx)인지 확인 해야합니다 .

실제로는 이전 코드 포인트로 이동하는 것이 일정한 시간에 수행 될 수 있고 코드 포인트의 중간에 대한 포인터가 고정 될 수있는보다 효율적인 인코딩 체계가 있습니다. 다음 코드를 허용하십시오.

X where X < 128
YX where 128 ≤ Y < 236, X < 128
ZYY where 236 ≤ Z < 256, 0 ≤ Y < 236. 

이전 3 바이트 중 하나가 236 이상이면 3 바이트 시퀀스의 시작입니다. 유효한 3 바이트 시퀀스 내에 2 바이트가있을 수 없기 때문입니다. 그렇지 않으면, 이전 2 바이트 중 하나가 ≥ 128 인 경우 2 바이트 시퀀스의 시작입니다. 그렇지 않으면 이전 바이트는 단일 바이트 <128입니다.

부분 문자열 검색이 약간 더 어려워집니다. 코드 포인트가 0 인 문자열에 0 바이트 만 포함되도록 0 바이트를 제외 할 수 있습니다.


언급 되지 않은 것은 – 이것은 실제로 @ratchet freak 's answer의 관찰에서 직접 오는 것이 아닙니다.
Piotr Dobrogost 11
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.