파이썬에서 파일을 읽고 쓰는 유니 코드 (UTF-8)


329

텍스트를 읽고 파일로 쓰는 것을 이해하는 데 약간의 두뇌 장애가 있습니다 (Python 2.4).

# The string, which has an a-acute in it.
ss = u'Capit\xe1n'
ss8 = ss.encode('utf8')
repr(ss), repr(ss8)

( "u'Capit \ xe1n '", "'Capit \ xc3 \ xa1n '")

print ss, ss8
print >> open('f1','w'), ss8

>>> file('f1').read()
'Capit\xc3\xa1n\n'

그래서 내가 Capit\xc3\xa1n좋아하는 편집기 인 파일 f2에 입력합니다.

그때:

>>> open('f1').read()
'Capit\xc3\xa1n\n'
>>> open('f2').read()
'Capit\\xc3\\xa1n\n'
>>> open('f1').read().decode('utf8')
u'Capit\xe1n\n'
>>> open('f2').read().decode('utf8')
u'Capit\\xc3\\xa1n\n'

내가 여기서 이해하지 못하는 것은 무엇입니까? 분명히 내가 놓친 몇 가지 중요한 마법 (또는 좋은 감각)이 있습니다. 적절한 변환을 위해 텍스트 파일에 한 가지 유형이 있습니까?

내가 정말로 여기에서 실패한 것은 UTF-8 표현의 요점은 실제로 외부에서 올 때 파이썬이 그것을 인식하도록 할 수 없다면입니다. 어쩌면 JSON은 문자열을 덤프하고 대신 사용할 수 있습니다. 요컨대, 파일에서 올 때 파이썬이 인식하고 디코딩 할이 유니 코드 객체의 ASCII 표현이 있습니까? 그렇다면 어떻게 얻습니까?

>>> print simplejson.dumps(ss)
'"Capit\u00e1n"'
>>> print >> file('f3','w'), simplejson.dumps(ss)
>>> simplejson.load(open('f3'))
u'Capit\xe1n'

답변:


110

표기법에서

u'Capit\xe1n\n'

"\ xe1"은 1 바이트 만 나타냅니다. "\ x"는 "e1"이 16 진수임을 나타냅니다. 당신이 쓸 때

Capit\xc3\xa1n

파일에 "\ xc3"이 있습니다. 그것들은 4 바이트이며 코드에서 모두 읽습니다. 당신이 그들을 표시 할 때 이것을 볼 수 있습니다 :

>>> open('f2').read()
'Capit\\xc3\\xa1n\n'

백 슬래시가 백 슬래시를 이스케이프 한 것을 볼 수 있습니다. 따라서 문자열에는 "\", "x", "c"및 "3"의 4 바이트가 있습니다.

편집하다:

다른 사람들이 답변에서 지적했듯이 편집기에 문자를 입력하면 편집기가 UTF-8 로의 변환을 처리하고 저장해야합니다.

실제로이 형식의 문자열이있는 경우 string_escape코덱을 사용하여 일반 문자열로 디코딩 할 수 있습니다 .

In [15]: print 'Capit\\xc3\\xa1n\n'.decode('string_escape')
Capitán

결과는 악센트 문자가 \\xc3\\xa1원래 문자열 로 작성된 2 바이트로 표시되는 UTF-8로 인코딩 된 문자열입니다. 유니 코드 문자열을 원한다면 UTF-8로 다시 디코딩해야합니다.

편집 : 파일에 UTF-8이 없습니다. 실제로 어떻게 보일지 보려면 :

s = u'Capit\xe1n\n'
sutf8 = s.encode('UTF-8')
open('utf-8.out', 'w').write(sutf8)

파일 utf-8.out내용을 편집기로 저장 한 파일 내용과 비교하십시오 .


그렇다면 파이썬이 파일을 사용하여 파일을 읽을 수 있다면 utf-8 인코딩 형식의 요점은 무엇입니까? 즉, 파이썬이 \ xc3에서 1 바이트로 읽는 ASCII 표현이 있습니까?
Gregg Lind

4
"그래, 요점은 ..."질문에 대한 대답은 "Mu"입니다. (Python은 UTF-8로 인코딩 된 파일을 읽을 수 있으므로). 두 번째 질문 : \ xc3은 ASCII 세트의 일부가 아닙니다. 아마도 "8 비트 인코딩"을 의미 할 것입니다. 유니 코드와 인코딩에 대해 혼란스러워합니다. 괜찮습니다. 많은 사람들이 있습니다.
tzot

8
이것을 프라이머로 읽어보십시오 : joelonsoftware.com/articles/Unicode.html
tzot

참고 : 문자 인코딩에 따라 1 바이트 이상을 사용하여 나타낼 수있는 u'\xe1'하나의 유니 코드 코드 포인트 U+00e1입니다 (utf-8에서는 2 바이트). (번호 225)가 나타낼 수있는 경우 어떤 문자 특성에 따라 한 바이트는 예를 디코딩하는데 사용될 인코딩을, 그 것이다 ( ) CP1251의, ( ) CP866에 등b'\xe1'бU+0431сU+0441
JFS

11
영국의 많은 코더들이 "아스키를 사용한다"고 말한 다음 £ 부호가 아니라는 것을 깨닫지 못하는 것은 놀라운 일입니다. 대부분 ascii! = 로컬 코드 페이지 (예 : latin1)를 인식하지 못합니다.
Danny Staple

712

인코딩 및 디코딩 방법을 망칠 필요없이 파일을 열 때 인코딩을 지정하는 것이 더 쉽다는 것을 알았습니다. 이 io모듈 (Python 2.6에 추가)은 io.open인코딩 매개 변수가있는 함수를 제공합니다 .

io모듈 에서 open 메소드를 사용하십시오 .

>>>import io
>>>f = io.open("test", mode="r", encoding="utf-8")

그런 다음 f의 read () 함수를 호출하면 인코딩 된 유니 코드 객체가 반환됩니다.

>>>f.read()
u'Capit\xe1l\n\n'

Python 3에서 io.open함수는 내장 함수의 별명입니다 open. 내장 된 open 함수는 Python 2가 아닌 Python 3의 인코딩 인수 만 지원합니다.

편집 : 이전에는이 ​​답변에서 코덱 모듈을 권장했습니다 . 코덱 모듈은 혼합 할 때 문제가 발생할 수 read()readline() 이 대답은 지금은 권장하므로, IO 대신 모듈을.

코덱 모듈에서 open 메소드를 사용하십시오.

>>>import codecs
>>>f = codecs.open("test", "r", "utf-8")

그런 다음 f의 read () 함수를 호출하면 인코딩 된 유니 코드 객체가 반환됩니다.

>>>f.read()
u'Capit\xe1l\n\n'

파일 인코딩을 알고 있다면 코덱 패키지를 사용하는 것이 훨씬 덜 혼란 스러울 것입니다.

http://docs.python.org/library/codecs.html#codecs.open을 참조 하십시오.


74
대신, 너무 파일을 작성하기위한 완벽하게 작동 open(file,'w')codecs.open(file,'w','utf-8')해결
매트 코놀리

1
이것은 내가 찾던 답이다 :)
Justin

6
codecs.open(...)방법은 with open(...):스타일 을 완전히 준수 with합니까? 결국 파일을 닫는 것이 중요합니까? 어쨌든 작동하는 것 같습니다.
try-catch-finally 마지막으로

2
@ try-catch-finally 예. 나는 with codecs.open(...) as f:항상 사용 합니다.
Tim Swast

6
나는 이것을 백 번 투표 할 수 있으면 좋겠다. 여러 데이터가 혼합되어 발생하는 인코딩 문제에 대해 며칠 동안 고통을 겪고 인코딩에 대한 외견을 읽은 후이 답변은 사막의 물과 같습니다. 더 빨리 보길 바랍니다.
마이크 지라드

45

이제 Python3에 필요한 것은 open(Filename, 'r', encoding='utf-8')

[요청 된 설명을 위해 2016-02-10에 편집]

Python3은 인코딩 매개 변수를 열린 함수에 추가했습니다 . 열기 기능에 대한 다음 정보는 여기에서 수집됩니다. https://docs.python.org/3/library/functions.html#open

open(file, mode='r', buffering=-1, 
      encoding=None, errors=None, newline=None, 
      closefd=True, opener=None)

인코딩은 파일을 디코딩하거나 인코딩하는 데 사용되는 인코딩의 이름입니다. 텍스트 모드에서만 사용해야합니다. 기본 인코딩은 플랫폼에 따라 다르지만 ( locale.getpreferredencoding ()이 반환하는 방식) Python에서 지원하는 모든 텍스트 인코딩을 사용할 수 있습니다. 지원되는 인코딩 목록은 코덱 모듈을 참조하십시오 .

따라서 encoding='utf-8'open 함수에 매개 변수로 추가 하면 파일 읽기 및 쓰기가 모두 utf8 (이제 Python에서 수행되는 모든 작업의 ​​기본 인코딩 임)로 수행됩니다.


제공하는 솔루션에 대한 설명을 조금 더 추가하여 답변을 더 자세히 설명해 주시겠습니까?
abarisone

2
그것은이 파이썬 코덱을 사용하여 2에서 사용할 수 있습니다 보인다는 모듈 - codecs.open('somefile', encoding='utf-8') stackoverflow.com/a/147756/149428을
테일러 Edmiston

18

그래서, 내가 찾고있는 솔루션을 찾았습니다.

print open('f2').read().decode('string-escape').decode("utf-8")

여기에 유용한 몇 가지 특이한 코덱이 있습니다. 이 특정 읽기를 통해 Python 내에서 UTF-8 표현을 가져 와서 ASCII 파일로 복사하여 유니 코드로 읽을 수 있습니다. "문자열 이스케이프"디코드에서는 슬래시가 두 배가되지 않습니다.

이것은 내가 상상했던 일종의 왕복 여행을 허용합니다.


1
좋은 반응, 나는 두 가지 솔루션을 모두 테스트 했으며 (codecs.open(file,"r","utf-8")간단 open(file,"r").read().decode("utf-8")하고 완벽하게 작동했습니다.
Eagle

"TypeError : 예상 str, 바이트 또는 os.PathLike 객체가 아닌 _io.TextIOWrapper"가 표시됩니다. 이유가 무엇입니까?
JinSnow

나는 upvotes의 수를 고려할 때 두 번째 대답을 받아들이는 것이 좋을 것이라고 생각합니다. :)
Jacquot

14
# -*- encoding: utf-8 -*-

# converting a unknown formatting file in utf-8

import codecs
import commands

file_location = "jumper.sub"
file_encoding = commands.getoutput('file -b --mime-encoding %s' % file_location)

file_stream = codecs.open(file_location, 'r', file_encoding)
file_output = codecs.open(file_location+"b", 'w', 'utf-8')

for l in file_stream:
    file_output.write(l)

file_stream.close()
file_output.close()

14

실제로 이것은 Python 3.2에서 UTF-8 인코딩으로 파일을 읽는 데 도움이되었습니다.

import codecs
f = codecs.open('file_name.txt', 'r', 'UTF-8')
for line in f:
    print(line)

6

유니 코드 문자열을 읽은 다음 HTML로 보내려면 다음과 같이하십시오.

fileline.decode("utf-8").encode('ascii', 'xmlcharrefreplace')

파이썬 기반 http 서버에 유용합니다.


6

인코딩의 일반적인 문제를 우연히 발견했습니다. 파일 인코딩이 무엇인지 어떻게 알 수 있습니까?

답 : 파일 형식이이를 제공 하지 않으면 할 수 없습니다 . 예를 들어 XML은 다음으로 시작합니다.

<?xml encoding="utf-8"?>

이 헤더는 인코딩과 상관없이 읽을 수 있도록 신중하게 선택되었습니다. 귀하의 경우에는 그러한 힌트가 없으므로 편집기 나 Python은 무슨 일이 일어나고 있는지 전혀 모릅니다. 따라서 파이썬에서 누락 된 비트를 제공하는 codecs모듈을 사용해야 codecs.open(path,mode,encoding)합니다.

편집기의 경우 파일 인코딩을 설정하는 방법을 제공하는지 확인해야합니다.

UTF-8의 요점은 21 비트 문자 (유니 코드)를 8 비트 데이터 스트림으로 인코딩 할 수있는 것입니다 (전 세계의 모든 컴퓨터가 처리 할 수있는 유일한 것이므로). 그러나 대부분의 OS는 유니 코드 시대보다 오래 되었기 때문에 하드 디스크의 파일에 인코딩 정보를 첨부 할 수있는 적절한 도구가 없습니다.

다음 문제는 파이썬 표현입니다. 이것은 heikogerlach의견에 완벽하게 설명되어 있습니다 . 콘솔은 ASCII 만 표시 할 수 있음을 이해해야합니다. 유니 코드 또는> = charcode 128을 표시하려면 이스케이프 방법을 사용해야합니다. 편집기에서 이스케이프 된 표시 문자열을 입력하지 말고 문자열의 의미를 입력해야합니다 (이 경우 움라우트를 입력하고 파일을 저장해야 함).

즉, 파이썬 함수 eval ()을 사용하여 이스케이프 된 문자열을 문자열로 바꿀 수 있습니다.

>>> x = eval("'Capit\\xc3\\xa1n\\n'")
>>> x
'Capit\xc3\xa1n\n'
>>> x[5]
'\xc3'
>>> len(x[5])
1

보다시피 문자열 "\ xc3"는 단일 문자로 바뀌 었습니다. 이것은 이제 UTF-8로 인코딩 된 8 비트 문자열입니다. 유니 코드를 얻으려면 :

>>> x.decode('utf-8')
u'Capit\xe1n\n'

Gregg Lind 는 다음과 같이 물었습니다. 여기에 누락 된 부분이 있다고 생각합니다. f2 파일에 hex :

0000000: 4361 7069 745c 7863 335c 7861 316e  Capit\xc3\xa1n

codecs.open('f2','rb', 'utf-8')예를 들어, 별도의 문자로 모두 읽습니다 (예상) ASCII로 파일에 쓸 수있는 방법이 있습니까?

답 : 그것은 당신이 의미하는 바에 달려 있습니다. ASCII는 127자를 초과하는 문자를 나타낼 수 없습니다. 따라서 "다음 x 자"는 "\ x"순서와 같은 "특별한 의미"를 나타내는 방법이 필요합니다. 다음 두 문자는 단일 문자의 코드입니다. "\ u"는 최대 0xFFFF (65535)의 유니 코드를 인코딩하기 위해 네 문자를 사용하여 동일하게 수행됩니다.

따라서 ASCII에는 동일한 문자가 포함되어 있지 않기 때문에 유니 코드를 ASCII에 직접 쓸 수 없습니다. f2에서와 같이 문자열 이스케이프로 쓸 수 있습니다. 이 경우 파일을 ASCII로 표시 할 수 있습니다. 또는 UTF-8로 쓸 수 있으며,이 경우 8 비트 안전 스트림이 필요합니다.

사용하는 솔루션 decode('string-escape')이 작동하지만 사용하는 메모리 양을 알고 있어야합니다 codecs.open().

파일은 8 비트의 바이트 시퀀스 일뿐입니다. 비트도 바이트도 의미가 없습니다. "65는 'A'를 의미합니다"라고 말하는 것은 당신입니다. 때문에 \xc3\xa1"A"가되어야하지만 컴퓨터가 알 수있는 방법이 없습니다, 당신은 파일을 기록 할 때 사용 된 인코딩을 지정하여이를 알려야합니다.


여기에 누락 된 부분이 있다고 생각합니다. 파일 f2에 포함 된 파일 : 16 진수 : 0000000 : 4361 7069 745c 7863 335c 7861 316e 0a Capit \ xc3 \ xa1n. 예를 들어 codecs.open ( 'f2', 'rb', 'utf-8')은 별도의 문자로 모두 읽습니다 (예상) ASCII 파일을 쓸 수있는 방법이 있습니까?
Gregg Lind

6

를 제외하고는 Python2 또는 Python3을 codecs.open()사용 io.open()하여 유니 코드 파일을 읽고 쓸 수 있습니다.

import io

text = u'á'
encoding = 'utf8'

with io.open('data.txt', 'w', encoding=encoding, newline='\n') as fout:
    fout.write(text)

with io.open('data.txt', 'r', encoding=encoding, newline='\n') as fin:
    text2 = fin.read()

assert text == text2


예, io를 사용하는 것이 좋습니다. 그러나 다음 with io.open('data.txt', 'w', 'utf-8') as file:과 같은 with 문을 작성하고 오류가 발생했습니다 TypeError: an integer is required. 내가 바꾼 후 with io.open('data.txt', 'w', encoding='utf-8') as file:효과가있었습니다.
Evan Hu

5

좋아하는 텍스트 편집기는 \xc3\xa1문자 리터럴이어야 한다는 것을 인식하지 못하지만 텍스트로 해석합니다. 그렇기 때문에 마지막 줄에 이중 백 슬래시가 표시됩니다. 이제 실제 백 슬래시가됩니다.xc3 파일에 등이 있습니다.

파이썬으로 인코딩 된 파일을 읽고 쓰려면 코덱을 가장 잘 사용하십시오. 모듈을 .

어떤 프로그램이 어떤 인코딩을 사용하여 텍스트를 해석할지 모르기 때문에 터미널과 응용 프로그램 사이에 텍스트를 붙여 넣기가 어렵습니다. 다음을 시도해 볼 수 있습니다.

>>> s = file("f1").read()
>>> print unicode(s, "Latin-1")
Capitán

그런 다음이 문자열을 편집기에 붙여넣고 Latin-1을 사용하여 저장했는지 확인하십시오. 클립 보드가 문자열을 왜곡하지 않는다고 가정하면 왕복이 작동합니다.


4

\ x .. 시퀀스는 파이썬에 특정한 것입니다. 범용 바이트 이스케이프 시퀀스가 ​​아닙니다.

UTF-8로 인코딩 된 비 ASCII로 실제로 입력하는 방법은 OS 및 / 또는 편집기에 따라 다릅니다. Windows에서 수행하는 방법은 다음과 같습니다 . OS X가 급성 악센트로 a 를 입력 하려면 option+ E를 누른 다음 AOS X의 거의 모든 텍스트 편집기가 UTF-8을 지원합니다.


3

또한 open()함수를 사용 하여 원래 파일을 대체하여 유니 코드 파일에서 작동 하도록 원래 기능을 향상시킬 수 있습니다 partial. 이 솔루션의 장점은 이전 코드를 변경할 필요가 없다는 것입니다. 투명하다.

import codecs
import functools
open = functools.partial(codecs.open, encoding='utf-8')

1

Python 2.7.9를 사용하여 iCal 을 구문 분석하려고했습니다 .

icalendar 가져 오기 일정에서

그러나 나는 얻고 있었다 :

 Traceback (most recent call last):
 File "ical.py", line 92, in parse
    print "{}".format(e[attr])
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe1' in position 7: ordinal not in range(128)

그리고 그것은 단지 고정되었습니다 :

print "{}".format(e[attr].encode("utf-8"))

이제 liké á böss를 인쇄 할 수 있습니다.


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