[python] Python str 대 유니 코드 유형
파이썬 2.7 작업, 나는 진짜 장점은 형식을 사용하여이 무엇인지 궁금하네요 unicode
대신 str
둘 다 유니 코드 문자열을 보유 할 수있을 것 같은. unicode
이스케이프 문자를 사용하여 문자열에 유니 코드 코드를 설정할 수 있다는 것 외에 특별한 이유가 \
있습니까? :
다음을 사용하여 모듈 실행 :
# -*- coding: utf-8 -*-
a = 'á'
ua = u'á'
print a, ua
결과 : á, á
편집하다:
Python 셸을 사용한 추가 테스트 :
>>> a = 'á'
>>> a
'\xc3\xa1'
>>> ua = u'á'
>>> ua
u'\xe1'
>>> ua.encode('utf8')
'\xc3\xa1'
>>> ua.encode('latin1')
'\xe1'
>>> ua
u'\xe1'
따라서 unicode
문자열은 latin1
대신 사용하여 인코딩되는 것처럼 보이고 utf-8
원시 문자열은 utf-8
? 나는 지금 더 혼란스러워! :에스
답변
unicode
텍스트 를 처리하기위한 것 입니다. 텍스트는 단일 바이트보다 클 수 있는 일련의 코드 포인트 입니다 . 텍스트 수 부호화 원시 바이트로 텍스트를 나타 내기 위해 특정 인코딩 (예 , …).utf-8
latin-1
참고 unicode
인코딩되지 않은 ! 파이썬에서 사용하는 내부 표현은 구현 세부 사항이며 원하는 코드 포인트를 표현할 수있는 한 신경 쓰지 않아야합니다.
반대로 str
Python 2에서는 일반 바이트 시퀀스입니다 . 텍스트를 나타내지 않습니다!
unicode
를 통해 표현되는 이진 데이터 시퀀스로 다양한 방식으로 인코딩 될 수있는 일부 텍스트의 일반적인 표현으로 생각할 수 있습니다 str
.
참고 : Python 3에서는 unicode
로 이름이 바뀌 었으며 일반 바이트 시퀀스에 대한 str
새로운 bytes
유형이 있습니다.
확인할 수있는 몇 가지 차이점은 다음과 같습니다.
>>> len(u'à') # a single code point
1
>>> len('à') # by default utf-8 -> takes two bytes
2
>>> len(u'à'.encode('utf-8'))
2
>>> len(u'à'.encode('latin1')) # in latin1 it takes one byte
1
>>> print u'à'.encode('utf-8') # terminal encoding is utf-8
à
>>> print u'à'.encode('latin1') # it cannot understand the latin1 byte
�
를 사용 str
하면 특정 인코딩 표현의 단일 바이트에 대한 하위 수준 제어가있는 반면를 사용 unicode
하면 코드 포인트 수준에서만 제어 할 수 있습니다. 예를 들어 다음을 수행 할 수 있습니다.
>>> 'àèìòù'
'\xc3\xa0\xc3\xa8\xc3\xac\xc3\xb2\xc3\xb9'
>>> print 'àèìòù'.replace('\xa8', '')
à�ìòù
이전에 유효한 UTF-8은 더 이상 아닙니다. 유니 코드 문자열을 사용하면 결과 문자열이 유효한 유니 코드 텍스트가 아닌 방식으로 작동 할 수 없습니다. 코드 포인트를 제거하고 코드 포인트를 다른 코드 포인트로 대체 할 수는 있지만 내부 표현을 망칠 수는 없습니다.
답변
유니 코드와 인코딩은 완전히 다르며 관련이 없습니다.
유니 코드
각 문자에 숫자 ID를 할당합니다.
- 0x41 → A
- 0xE1 → á
- 0x414 → Д
따라서 유니 코드는 A에 0x41, á에 0xE1, Д에 0x414를 할당합니다.
내가 사용한 작은 화살표조차도 유니 코드 번호가 0x2192입니다. 그리고 이모티콘에도 유니 코드 번호가 있습니다. ?는 0x1F602입니다.
이 표 에있는 모든 문자의 유니 코드 번호를 조회 할 수 있습니다 . 특히 위의 처음 세 글자 , 여기 에 화살표, 여기 에 그림 이모티콘을 찾을 수 있습니다 .
유니 코드로 모든 문자에 할당 된 이러한 숫자를 코드 포인트 라고 합니다 .
이 모든 것의 목적은 각 문자를 명확하게 참조하는 수단을 제공하는 것입니다. 예를 들어, 내가 ?에 대해 이야기하고 있다면, “당신도 알다시피 눈물을 흘리는이 웃음 이모티콘” 이라고 말하는 대신 유니 코드 코드 포인트 0x1F602 라고 말할 수 있습니다 . 더 쉬웠 죠?
유니 코드 코드 포인트는 일반적으로 선행으로 형식이 지정되고 U+
16 진수 값은 4 자리 이상으로 채워집니다. 따라서 위의 예는 U + 0041, U + 00E1, U + 0414, U + 2192, U + 1F602입니다.
유니 코드 코드 포인트의 범위는 U + 0000에서 U + 10FFFF입니다. 그것은 1,114,112 개의 숫자입니다. 이 숫자 중 2048 개가 서로 게이트 에 사용되므로 1,112,064 개가 남아 있습니다. 즉, 유니 코드는 1,112,064 개의 고유 문자에 고유 ID (코드 포인트)를 할당 할 수 있습니다. 이 모든 코드 포인트가 아직 문자에 할당 된 것은 아니며 유니 코드는 지속적으로 확장됩니다 (예 : 새 이모 지 도입시).
기억해야 할 중요한 점은 유니 코드가 수행하는 모든 작업은 쉽고 명확한 참조를 위해 각 문자에 코드 포인트라는 숫자 ID를 할당하는 것입니다.
인코딩
문자를 비트 패턴에 매핑합니다.
이러한 비트 패턴은 컴퓨터 메모리 또는 디스크의 문자를 나타내는 데 사용됩니다.
다양한 문자 하위 집합을 다루는 다양한 인코딩이 있습니다. 영어권 세계에서 가장 일반적인 인코딩은 다음과 같습니다.
ASCII
지도 128 자 길이 7의 비트 패턴에 (U + 007F에 코드 포인트 U + 0000).
예:
- a → 1100001 (0x61)
이 테이블 에서 모든 매핑을 볼 수 있습니다 .
ISO 8859-1 (일명 Latin-1)
매핑 191 자 길이 8 비트 패턴에 (U + 0020 U + 00FF에 U + 007E 및 U + 00A0에 코드 포인트).
예:
- a → 01100001 (0x61)
- á → 11100001 (0xE1)
이 테이블 에서 모든 매핑을 볼 수 있습니다 .
UTF-8
지도 1,112,064 자 중 길이가 8, 16, 24, 또는 32 비트의 비트 패턴들 (기존의 유니 코드 코드 포인트) (즉, 1, 2, 3 또는 4 바이트).
예:
- a → 01100001 (0x61)
- á → 11000011 10100001 (0xC3 0xA1)
- ≠ → 11100010 10001001 10100000 (0xE2 0x89 0xA0)
- ? → 11110000 10011111 10011000 10000010 (0xF0 0x9F 0x98 0x82)
UTF-8이 문자를 비트 문자열로 인코딩하는 방법은 여기에 잘 설명되어 있습니다 .
유니 코드 및 인코딩
위의 예를 살펴보면 유니 코드가 얼마나 유용한 지 분명해집니다.
예를 들어 내가 Latin-1 이고 á의 인코딩을 설명하고 싶다면 다음과 같이 말할 필요가 없습니다.
“나는 aigu를 사용하여 (또는 상승 막대라고 부르는)이를 11100001로 인코딩합니다.”
하지만 다음과 같이 말할 수 있습니다.
“U + 00E1을 11100001로 인코딩합니다.”
그리고 내가 UTF-8 이라면 다음과 같이 말할 수 있습니다.
“저는 차례로 U + 00E1을 11000011 10100001로 인코딩합니다.”
그리고 우리가 의미하는 캐릭터는 모두에게 분명합니다.
이제 종종 발생하는 혼란에
이진수로 해석하면 인코딩의 비트 패턴이이 문자의 유니 코드 코드 포인트와 같을 때도 있습니다.
예를 들면 :
- 아스키 인코딩 은 16 진수로 해석 할 수 1,100,001, 등 이 0x61 , 그리고 유니 코드 코드 포인트 a는 이다 U + 0061 .
- Latin-1은 á 를 11100001로 인코딩 하며, 16 진수 0xE1 로 해석 할 수 있으며 á 의 유니 코드 코드 포인트 는 U + 00E1 입니다.
물론 이것은 편의상 의도적으로 이렇게 배열되었습니다. 그러나 당신은 그것을 순수한 우연의 일치 로보아야합니다 . 메모리에서 문자를 나타내는 데 사용되는 비트 패턴은이 문자의 유니 코드 코드 포인트에 어떤 식 으로든 연결되어 있지 않습니다.
아무도 11100001과 같은 비트 문자열을 이진수로 해석해야한다고 말하지도 않습니다. Latin-1이 문자 á 를 인코딩하는 데 사용하는 비트 시퀀스로보십시오 .
질문으로 돌아 가기
Python 인터프리터에서 사용하는 인코딩은 UTF-8 입니다.
귀하의 예에서 진행되는 작업은 다음과 같습니다.
예 1
다음은 문자 á를 UTF-8로 인코딩합니다. 그 결과 변수에 저장된 11000011 10100001 비트 문자열이 생성됩니다 a
.
>>> a = 'á'
의 값을 볼 때 a
내용 11000011 10100001은 16 진수 0xC3 0xA1로 형식이 지정되고 다음과 같이 출력됩니다 '\xc3\xa1'
.
>>> a
'\xc3\xa1'
예 2
다음은 U + 00E1 인 á의 유니 코드 코드 포인트를 변수에 ua
저장합니다 (Python이 내부적으로 메모리에서 코드 포인트 U + 00E1을 표현하기 위해 어떤 데이터 형식을 사용하는지 알지 못하며 중요하지 않습니다).
>>> ua = u'á'
의 값을 볼 때 ua
Python은 코드 포인트 U + 00E1이 포함되어 있음을 알려줍니다.
>>> ua
u'\xe1'
예제 3
다음은 UTF-8로 유니 코드 코드 포인트 U + 00E1 (문자 á를 나타냄)을 인코딩하여 결과적으로 비트 패턴 11000011 10100001이됩니다. 다시 출력을 위해이 비트 패턴은 16 진수 0xC3 0xA1로 표시됩니다.
>>> ua.encode('utf-8')
'\xc3\xa1'
예 4
다음은 유니 코드 코드 포인트 U + 00E1 (문자 á를 나타냄)을 Latin-1로 인코딩하여 결과적으로 비트 패턴 11100001이됩니다. 출력의 경우이 비트 패턴은 16 진수 0xE1로 표시되며 이는 우연히 초기 값과 동일합니다. 코드 포인트 U + 00E1 :
>>> ua.encode('latin1')
'\xe1'
유니 코드 개체 ua
와 Latin-1 인코딩 사이에는 관계가 없습니다 . á의 코드 포인트는 U + 00E1이고 á의 Latin-1 인코딩은 0xE1 (인코딩의 비트 패턴을 이진수로 해석하는 경우)이라는 것은 순수한 우연입니다.
답변
터미널이 UTF-8로 구성됩니다.
인쇄가 a
작동 한다는 사실 은 우연입니다. 원시 UTF-8 바이트를 터미널에 쓰고 있습니다. a
는 2 바이트, 16 진 값 C3 및 A1을 포함하는 길이 2 의 값이고 ,은 코드 포인트 U + 00E1을 포함하는 ua
길이 1 의 유니 코드 값입니다 .
이러한 길이 차이는 유니 코드 값을 사용하는 주요 이유 중 하나입니다. 바이트 문자열 의 텍스트 문자 수를 쉽게 측정 할 수 없습니다 . len()
바이트 문자열의 많은 문자 인코딩이 아닙니까 얼마나 많은 바이트가 사용 된 방법을 알려줍니다.
유니 코드 값을 다른 출력 인코딩으로 인코딩 하면 차이를 확인할 수 있습니다 .
>>> a = 'á'
>>> ua = u'á'
>>> ua.encode('utf8')
'\xc3\xa1'
>>> ua.encode('latin1')
'\xe1'
>>> a
'\xc3\xa1'
유니 코드 표준의 처음 256 개 코드 포인트는 Latin 1 표준과 일치하므로 U + 00E1 코드 포인트는 16 진수 값 E1을 가진 바이트로 Latin 1로 인코딩됩니다.
또한 Python은 유니 코드 및 바이트 문자열 표현에 이스케이프 코드를 사용하고 인쇄 할 수없는 ASCII 코드 포인트도 \x..
이스케이프 값을 사용하여 표현 합니다. 이런 이유로 128 255 외모 사이의 코드 포인트 유니 코드 문자열 단지 라틴어 1 인코딩있다. U + 00FF를 초과하는 코드 포인트가있는 유니 코드 문자열이있는 경우 \u....
4 자리 16 진수 값과 함께 다른 이스케이프 시퀀스 가 대신 사용됩니다.
유니 코드와 인코딩의 차이점이 무엇인지 아직 완전히 이해하지 못한 것 같습니다. 계속하기 전에 다음 기사를 읽으십시오.
-
모든 소프트웨어 개발자는 절대적으로 유니 코드 및 문자 집합에 대해 반드시 알아야합니다 (변명 없음!) by Joel Spolsky
-
Ned Batchelder의 실용적인 유니 코드
답변
a를 유니 코드로 정의하면 문자 a와 á가 동일합니다. 그렇지 않으면 á는 두 문자로 계산됩니다. len (a) 및 len (au)를 시도하십시오. 그 외에도 다른 환경에서 작업 할 때 인코딩이 필요할 수 있습니다. 예를 들어 md5를 사용하면 a와 ua에 대해 다른 값을 얻습니다.