파이썬 인터프리터가 문자열 작업에서 ASCII가 아닌 문자를 올바르게 처리하도록 만드는 방법은 무엇입니까?


104

다음과 같은 문자열이 있습니다.

6 918 417 712

이 문자열을 자르는 명확한 방법은 (파이썬을 이해했듯이) 단순히 문자열이라는 변수에 있다고 말하는 것입니다 s.

s.replace('Â ', '')

그게 트릭을해야합니다. 그러나 물론 '\xc2'blabla.py 파일 의 비 ASCII 문자 가 인코딩되지 않았다고 불평합니다 .

다른 인코딩으로 전환하는 방법을 이해할 수 없었습니다.

여기에 코드가 있습니다. 실제로는 위와 동일하지만 지금은 컨텍스트에 있습니다. 파일은 메모장에 UTF-8로 저장되며 다음 헤더가 있습니다.

#!/usr/bin/python2.4
# -*- coding: utf-8 -*-

코드:

f = urllib.urlopen(url)

soup = BeautifulSoup(f)

s = soup.find('div', {'id':'main_count'})

#making a print 's' here goes well. it shows 6Â 918Â 417Â 712

s.replace('Â ','')

save_main_count(s)

더 이상 얻지 못합니다 s.replace...


1
지금까지 4 개의 답변을 모두 시도했습니다. 안돼. 여전히 UnicodeDecodeError : 'ascii'코덱이 위치 1에서 0xc2 바이트를 디코딩 할 수 없습니다 (128)
adergaard

유니 코드 문자열 앞에 다음을 추가 해야합니다u
SilentGhost

@SilentGhost : 보시다시피 유니 코드 문자열인지 확인할 방법이 없습니다. 위에 표시된 내용이 포함 된 문자열을 얻었지만 ASCII가 아닌 문자열이 포함되어 있습니다. 그것이 진짜 문제입니다. 나는 처음 128에 아니기 때문에이 유니 코드 인 것 같은데요
adergaard

오류는 들어오는 문자열과 관련이 없습니다. 이 오류를 발생시키는 코드의 문자열입니다!
SilentGhost 2009-08-27

2
이것이 바로 이런 종류의 혼란을 피하기 위해 파이썬 3이 문자열과 바이트 시퀀스의 차이에 대해 엄격한 이유라고 확신합니다.
Mark Ransom

답변:


84

Python 2는 ascii소스 파일의 기본 인코딩으로 사용합니다. 즉, 리터럴에서 ASCII가 아닌 유니 코드 문자를 사용하려면 파일 맨 위에 다른 인코딩을 지정해야합니다. Python 3은 utf-8소스 파일의 기본 인코딩으로 사용 하므로 문제가되지 않습니다.

참조 : http://docs.python.org/tutorial/interpreter.html#source-code-encoding

utf-8 소스 인코딩을 활성화하려면 다음 두 줄 중 하나에 입력합니다.

# -*- coding: utf-8 -*-

위의 내용은 문서에 있지만 이것도 작동합니다.

# coding: utf-8

추가 고려 사항 :

  • 소스 파일은 텍스트 편집기에서도 올바른 인코딩을 사용하여 저장해야합니다.

  • Python 2에서 유니 코드 리터럴은 u앞에 가 있어야합니다 . s.replace(u"Â ", u"")그러나 Python 3에서 와 같이 따옴표 만 사용하십시오. Python 2에서는 Python from __future__ import unicode_literals3 동작을 얻을 수 있지만 이것이 현재 모듈 전체에 영향을 미친다는 점에 유의하십시오.

  • s.replace(u"Â ", u"")s유니 코드 문자열이 아닌 경우에도 실패 합니다.

  • string.replace 새 문자열을 반환하고 제자리에서 편집하지 않으므로 반환 값도 사용하고 있는지 확인하십시오.


4
실제로는 # coding: utf-8. -*-장식용은 아니지만 필요하지 않을 것입니다. 낡은 껍데기가 거기에 있었던 것 같아요.
fmalina 2013 년

157
def removeNonAscii(s): return "".join(filter(lambda x: ord(x)<128, s))

편집 : 내 첫 번째 충동은 항상 필터를 사용하는 것이지만 생성기 표현식이 더 메모리 효율적이고 짧습니다 ...

def removeNonAscii(s): return "".join(i for i in s if ord(i)<128)

이것은 UTF-8 인코딩과 함께 작동한다는 것을 명심하십시오 (멀티 바이트 문자의 모든 바이트는 가장 높은 비트가 1로 설정되기 때문입니다).


1
내가 얻는다 : TypeError : ord ()는 문자를 예상했지만 길이 2의 문자열을 찾았습니다
Ivelin

@Ivelin은 "문자"가 적절한 유니 코드로 해석되지 않기 때문입니다 ... u리터럴 인 경우 소스 문자열에 접두사가 있는지 확인합니다.
포트란

35
>>> unicode_string = u"hello aåbäcö"
>>> unicode_string.encode("ascii", "ignore")
'hello abc'

4
나는 당신이 얻은 표를 보았지만 그것을 시도하면 그것은 말한다 : 아니오. UnicodeDecodeError : 'ascii'코덱은 위치 1에서 0xc2 바이트를 디코딩 할 수 없습니다. 서 수가 범위 (128)에 없습니다. 내 원래 문자열이 유니 코드가 아닐 수 있습니까? 어쨌든. 필요합니다
adergaard 2009-08-27

2
좋아, 고마워. 결과에 .decode ()를 사용하여 원래 코딩으로 가져 오도록 제안해도 될까요?
AkiRoss 2011

UnicodeDecodeError : 'ascii'가 발생하면 인코딩 기능을 적용하기 전에 문자열을 ''UTF-8 '형식으로 변환 해보십시오.
Sateesh

16

다음 코드는 ASCII가 아닌 모든 문자를 물음표로 바꿉니다.

"".join([x if ord(x) < 128 else '?' for x in s])

궁금해서 알고 싶었어요. 물음표로 바꿔야 할 특별한 이유가 있나요?
Mohsin

6

Regex 사용 :

import re

strip_unicode = re.compile("([^-_a-zA-Z0-9!@#%&=,/'\";:~`\$\^\*\(\)\+\[\]\.\{\}\|\?\<\>\\]+|[^\s]+)")
print strip_unicode.sub('', u'6Â 918Â 417Â 712')

5

대답하기에는 너무 늦었지만 원래 문자열은 UTF-8이고 '\ xc2 \ xa0'은 NO-BREAK SPACE의 경우 UTF-8입니다. 원래 문자열을 s.decode('utf-8')(\ xa0이 Windows-1252 또는 latin-1로 잘못 디코딩되면 공백으로 표시됨) 으로 간단히 디코딩합니다 .

예 (Python 3)

s = b'6\xc2\xa0918\xc2\xa0417\xc2\xa0712'
print(s.decode('latin-1')) # incorrectly decoded
u = s.decode('utf8') # correctly decoded
print(u)
print(u.replace('\N{NO-BREAK SPACE}','_'))
print(u.replace('\xa0','-')) # \xa0 is Unicode for NO-BREAK SPACE

산출

6 918 417 712
6 918 417 712
6_918_417_712
6-918-417-712

3
#!/usr/bin/env python
# -*- coding: utf-8 -*-

s = u"6Â 918Â 417Â 712"
s = s.replace(u"Â", "") 
print s

이것은 인쇄됩니다 6 918 417 712


아니. UnicodeDecodeError : 'ascii'코덱은 위치 1에서 0xc2 바이트를 디코딩 할 수 없습니다. 서 수가 범위 (128)에 없습니다. 내 원래 문자열이 유니 코드가 아닐 수 있습니까? 어쨌든. 나는 아마도 뭔가 잘못하고있을 것입니다.
adergaard

@adergaard, 소스 파일 상단에 #-- coding : utf- 8--추가 했 습니까?
Nadia Alramli

예,이 페이지의 맨 위를 다시보십시오. 질문을 편집하고 코드와 헤더 주석을 입력했습니다. 도와 주셔서 감사합니다.
adergaard

유니 코드로 html 또는 xml 문서에서 문자열을 얻는 방법을 알아 내야한다고 생각합니다. 여기에 대한 자세한 정보 : diveintopython.org/xml_processing/unicode.html
Isaiah

2

나는 그것이 오래된 스레드라는 것을 알고 있지만, 128 이상의 모든 문자 코드 (또는 필요한 경우 다른 코드)를 대체 할 수있는 좋은 방법 인 translate 메서드를 언급해야한다는 강박감을 느꼈습니다.

사용법 : str. 번역 ( table [, deletechars] )

>>> trans_table = ''.join( [chr(i) for i in range(128)] + [' '] * 128 )

>>> 'Résultat'.translate(trans_table)
'R sultat'
>>> '6Â 918Â 417Â 712'.translate(trans_table)
'6  918  417  712'

Python 2.6 부터는 테이블을 None으로 설정하고 http://docs.python.org/library/stdtypes 의 표준 문서에 표시된 예제 에서처럼 원하지 않는 문자를 deletechars 를 사용 하여 삭제할 수도 있습니다 . html .

유니 코드 문자열을 사용하면 변환 테이블은 256 자 문자열이 아니라 관련 문자의 ord ()를 키로 사용하는 dict입니다. 그러나 어쨌든 유니 코드 문자열에서 적절한 ASCII 문자열을 얻는 것은 위의 truppo에서 언급 한 방법을 사용하여 충분히 간단합니다. 즉, unicode_string.encode ( "ascii", "ignore")

요약하자면 어떤 이유로 ASCII 문자열을 가져와야하는 경우 (예 raise Exception, ascii_message:를 사용하여 표준 예외를 발생 시키는 경우) 다음 함수를 사용할 수 있습니다.

trans_table = ''.join( [chr(i) for i in range(128)] + ['?'] * 128 )
def ascii(s):
    if isinstance(s, unicode):
        return s.encode('ascii', 'replace')
    else:
        return s.translate(trans_table)

번역의 좋은 점은 악센트가있는 문자를 단순히 삭제하거나 '?'로 바꾸는 대신 악센트가있는 관련 ASCII 문자 로 변환 할 수 있다는 것 입니다. 예를 들어 인덱싱 목적으로 유용합니다.


내가 얻는다 : TypeError : 문자 매핑은 정수, 없음 또는 유니 코드를 반환해야합니다
Ivelin


1

이것은 더러운 해킹이지만 작동 할 수 있습니다.

s2 = ""
for i in s:
    if ord(i) < 128:
        s2 += i

0

그만한 가치는 내 캐릭터 세트 였고 utf-8고전적인 " # -*- coding: utf-8 -*-"라인을 포함 시켰습니다 .

그러나 웹 페이지에서이 데이터를 읽을 때 Universal Newlines가 없다는 것을 발견했습니다.

내 텍스트에는 " \r\n"로 구분 된 두 단어가 있습니다. 나는에서 분할 \n하고 "\n".

반복해서 문제의 캐릭터 세트를 보았을 때 실수를 깨달았습니다.

따라서 ASCII 문자 집합 내에있을 수도 있지만 예상하지 못한 문자 일 수도 있습니다 .

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