Python str 대 유니 코드 유형


101

파이썬 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유니 코드 문자의 추상화 일뿐입니다. 일부 인코딩 unicode으로 변환 할 수 있습니다 str(예 :) utf-8.

답변:


178

unicode텍스트 를 처리하기위한 입니다. 텍스트는 단일 바이트보다 클 수 있는 일련의 코드 포인트 입니다 . 텍스트 수 부호화 원시 바이트로 텍스트를 나타 내기 위해 특정 인코딩 (예 , ...).utf-8latin-1

참고 unicode 인코딩되지 않은 ! 파이썬에서 사용하는 내부 표현은 구현 세부 사항이며 원하는 코드 포인트를 표현할 수있는 한 신경 쓰지 않아야합니다.

반대로 strPython 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은 더 이상 아닙니다. 유니 코드 문자열을 사용하면 결과 문자열이 유효한 유니 코드 텍스트가 아닌 방식으로 작동 할 수 없습니다. 코드 포인트를 제거하고 코드 포인트를 다른 코드 포인트로 대체 할 수는 있지만 내부 표현을 망칠 수는 없습니다.


4
답변 해 주셔서 감사합니다. 많은 도움이되었습니다! 저에게 가장 분명한 부분은 "유니 코드가 인코딩되지 않았습니다! 파이썬에서 사용하는 내부 표현은 구현 세부 사항이므로 신경 쓰지 마세요 [...]"입니다. 따라서 unicode객체 를 직렬화 할 때 값 encode()을 표현하기 위해 내부적으로 어떤 것이 사용되는지 알지 못하기 때문에 먼저 적절한 인코딩 형식 으로 명시 적으로 지정 해야한다고 생각 unicode합니다.
Caumons 2013-08-03

10
예. 일부 텍스트 (예 : 파일)를 저장하려면 바이트로 표시해야 합니다. 즉 인코딩 해야 합니다. 콘텐츠를 검색 할 때 바이트를 객체 로 디코딩 하려면 사용 된 인코딩을 알아야 unicode합니다.
Bakuriu 2013-08-03

죄송 합니다만 unicode인코딩되지 않은 진술 은 명백히 잘못되었습니다. UTF-16 / UCS-2 및 UTF-32 / UCS-4도 인코딩이며 앞으로 더 많이 생성 될 것입니다. 요점은 구현 세부 사항에 대해 신경을 써서는 안된다고 (실제로는 안됩니다!), 이것이 unicode인코딩 되지 않았다는 의미 는 아닙니다. 물론입니다. 그것이 .decode()'d가 될 수 있는지 여부 는 완전히 다른 이야기입니다.
0xC0000022L

1
@ 0xC0000022L 아마도 문장이 명확하지 않을 수도 있습니다. 그것은 말해야합니다 : unicode객체 내부 표현은 비표준을 포함하여 원하는 것이 될 수 있습니다. 특히 python3 + unicode 에서는 포함 된 데이터에 따라 변경되는 비표준 내부 표현을 사용합니다. 따라서 표준 인코딩 이 아닙니다 . 텍스트 표준으로서의 유니 코드는 텍스트 의 추상적 인 표현코드 포인트 만을 정의 합니다. 표준 utf-X 등을 포함하여 메모리에 유니 코드를 인코딩하는 방법은 많습니다. 파이썬은 효율성을 위해 자체 방식을 사용합니다.
Bakuriu

1
UTF-16 인코딩이 없다는 사실 또한 0xC0000022L @ 아무것도 CPython과의 함께 할 수있는 unicode이 때문에, 객체를 하지 않는 UTF-16이나 UTF-32을 사용합니다. 임시 표현을 사용하며 데이터를 실제 바이트로 인코딩하려면을 사용해야 encode합니다. 또한 언어 unicode는 구현 방법을 지시하지 않으므로 Python의 다른 버전 또는 구현은 다른 내부 표현을 가질 수 있습니다 .
Bakuriu

38

유니 코드와 인코딩은 완전히 다르며 관련이 없습니다.

유니 코드

각 문자에 숫자 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'á'

의 값을 볼 때 uaPython은 코드 포인트 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 (인코딩의 비트 패턴을 이진수로 해석하는 경우)이라는 것은 순수한 우연입니다.


31

터미널이 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 진수 값과 함께 다른 이스케이프 시퀀스 가 대신 사용됩니다.

유니 코드와 인코딩의 차이점이 무엇인지 아직 완전히 이해하지 못한 것 같습니다. 계속하기 전에 다음 기사를 읽으십시오.


추가 테스트를 통해 질문을 편집했습니다. 나는 한동안 유니 코드와 다른 인코딩에 대해 읽고 있었고 이론을 이해하고 있다고 생각하지만 실제로 파이썬 코드를 테스트 할 때 무슨 일이 일어나고 있는지
알지 못합니다

1
latin-1 인코딩은 유니 코드 표준의 처음 256 개 코드 포인트와 일치합니다. 이것이 U + 00E1 \xe1이 라틴어 1로 인코딩하는 이유입니다 .
Martijn Pieters

2
이것이 유니 코드에서 가장 중요한 부분입니다. 인코딩이 아닙니다 . 텍스트입니다. 유니 코드는 어떤 코드 포인트가 숫자인지에 대한 정보, 공백 또는 기타 범주 등을 왼쪽에서 오른쪽으로 또는 오른쪽에서 왼쪽으로 표시해야하는 등 훨씬 더 많은 것을 포함하는 표준입니다. 등
Martijn Pieters

1
유니 코드가 "인터페이스"와 같고 인코딩이 실제 "구현"과 같다고 말하는 것과 같습니다.
Caumons 2013-08-03

2
@Varun : 내부적으로 UCS-2를 사용하고 길이가 2 인 것으로 U + FFFF를 넘는 항목을 잘못 표시하는 Python 2 좁은 빌드를 사용해야합니다. Python 3 및 UCS-2 (와이드) 빌드는 길이가 실제로 1임을 보여줍니다.
Martijn Pieters

2

a를 유니 코드로 정의하면 문자 a와 á가 동일합니다. 그렇지 않으면 á는 두 문자로 계산됩니다. len (a) 및 len (au)를 시도하십시오. 그 외에도 다른 환경에서 작업 할 때 인코딩이 필요할 수 있습니다. 예를 들어 md5를 사용하면 a와 ua에 대해 다른 값을 얻습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.