파이썬에서 문자열이 ASCII인지 확인하는 방법?


211

문자열이 ASCII인지 여부를 확인하고 싶습니다.

나는 알고 ord()있지만 ord('é'), 시도 할 때 나는있다 TypeError: ord() expected a character, but string of length 2 found. 필자는 파이썬을 구축 한 방식으로 인해 발생한다는 것을 이해했습니다 ( ord()문서에 설명되어 있음 ).

확인하는 다른 방법이 있습니까?


문자열 인코딩은 Python 2와 Python 3에서 상당히 다르므로 어떤 버전을 타겟팅하고 있는지 아는 것이 좋습니다.
florisla

답변:


188
def is_ascii(s):
    return all(ord(c) < 128 for c in s)

95
무의미하게 비효율적입니다. Vincent Marchetti가 제안한 것처럼 s.decode ( 'ascii')를 시도하고 UnicodeDecodeError를 잡는 것이 훨씬 좋습니다.
ddaa

20
비효율적이지 않습니다. all ()은 유효하지 않은 바이트를 만나면 단락되고 False를 반환합니다.
John Millikin

10
비효율적이든 아니든간에, 더 파이썬적인 방법은 시도 / 제외입니다.
Jeremy Cantrell

43
시도 / 제외에 비해 비효율적입니다. 여기서 루프는 인터프리터에 있습니다. try / except 형식을 사용하면 루프는 str.decode ( 'ascii')에 의해 호출 된 C 코덱 구현에 있습니다. 그리고 나는 try / except 형식이 더 파이썬이라는 것에 동의합니다.
ddaa

25
@JohnMachin는 ord(c) < 128것보다 무한히 더 읽기 쉽고 직관적c <= "\x7F"
슬레이터 Victoroff

253

당신이 옳은 질문을하지 않는 것 같아요.

파이썬의 문자열에는 'ascii', utf-8 또는 기타 인코딩에 해당하는 속성이 없습니다. 문자열의 소스 (파일에서 읽거나 키보드에서 입력하는 등)는 문자열을 생성하기 위해 ASCII로 유니 코드 문자열을 인코딩했을 수 있지만 그 곳에서 답을 찾아야합니다.

아마도 당신이 물어볼 수있는 질문은 "이 문자열이 ASCII로 유니 코드 문자열을 인코딩 한 결과입니까?"입니다. -다음을 시도하여 답변 할 수 있습니다.

try:
    mystring.decode('ascii')
except UnicodeDecodeError:
    print "it was not a ascii-encoded unicode string"
else:
    print "It may have been an ascii-encoded unicode string"

28
python 3에서는 문자열이없는 디코딩 방법이기 때문에 encode를 사용하는 것이 좋습니다. 인코딩 / 디코딩의 차이점
Jet Guo

@Sri : 인코딩되지 않은 문자열 ( strPython 2, bytesPython 3)에서 사용하기 때문 입니다.
dotancohen

Python 2에서이 솔루션은 유니 코드 문자열 에서만 작동 합니다. str모든 ISO 인코딩에서 A 를 먼저 유니 코드로 인코딩해야합니다. 대답은 이것에 들어가야합니다.
Alexis

@JetGuo : s.decode('ascii') if isinstance(s, bytes) else s.encode('ascii')파이썬 3에서 입력 유형에 따라 두 가지를 모두 사용해야합니다. OP의 입력은 바이트 문자열 'é'(파이썬 2 구문, 파이썬 3은 당시에 릴리스되지 않았습니다)이므로 .decode()정확합니다.
jfs

2
@alexis : 잘못되었습니다. str파이썬 2에서는 바이트 문자열입니다. .decode('ascii')모든 바이트가 ASCII 범위에 있는지 확인하는 데 사용 하는 것이 좋습니다 .
jfs

153

파이썬 3 방법 :

isascii = lambda s: len(s) == len(s.encode())

확인하려면 테스트 문자열을 전달하십시오.

str1 = "♥O◘♦♥O◘♦"
str2 = "Python"

print(isascii(str1)) -> will return False
print(isascii(str2)) -> will return True

7
이것은 python3에서 거의 모든 문자열 인 유니 코드 문자열에서 ASCII가 아닌 문자를 감지하는 좋은 방법입니다. ASCII 문자는 1 바이트 만 사용하여 인코딩 할 수 있으므로 모든 ASCII 문자 길이는 바이트로 인코딩 된 후 크기에 따라 다릅니다. 반면 ASCII 이외의 다른 문자는 2 바이트 또는 3 바이트로 인코딩되어 크기가 커집니다.
Devy

@far로 가장 좋은 대답이지만…와 같은 일부 문자는 ascii처럼 보일 수 있습니다. 따라서 영어 텍스트를 감지하기 위해이 문자를 사용하려는 경우 확인하기 전에 이러한 문자를 대체해야합니다.
Christophe Roussy

1
그러나 Python2에서는 UnicodeEncodeError가 발생합니다. Py2와 Py3에 대한 솔루션을 찾았습니다
alvas

2
람다 사용에 익숙하지 않은 사람들을 위해 (이 답변을 처음 isasciiisascii('somestring')Trueisascii('àéç')False
접했

8
이것은 단지 낭비입니다. 문자열을 UTF-8로 인코딩하여 다른 전체 바이트 문자열을 만듭니다. 진정한 파이썬 3 방식은 try: s.encode('ascii'); return True except UnicodeEncodeError: return False(위와 비슷하지만 파이썬 3에서는 문자열이 유니 코드이므로 인코딩) 이 답변은 또한 대리가있을 때 Python 3에서 오류를 발생시킵니다 (예 : isascii('\uD800')반환하는 대신 오류 발생 False)
Artyer

72

Python 3.7의 새로운 기능 ( bpo32677 )

문자열에 대한 더 이상 번거롭고 비효율적 인 ASCII 검사, 새로운 내장 str/ bytes/ bytearray방법- .isascii()문자열이 ASCII인지 확인합니다.

print("is this ascii?".isascii())
# True

이것은 정상에 있어야합니다!
Salek

"\x03".isascii()또한 사실입니다. 문서에 따르면 모든 문자가 코드 포인트 128 (0-127) 미만인지 확인합니다. 제어 문자도 피하려면 다음이 필요 text.isascii() and text.isprintable()합니다.. 그냥 사용 isprintable자체 것은 ¿ 같은 문자가 (제대로) 인쇄로 간주되므로, 충분한 또한,하지만 당신은 모두 당신이 모두를 원하는 경우 확인해야합니다 그래서, 아스키 인쇄 섹션 내에 아니다. 또 다른 문제 : 공백은 인쇄 가능한 것으로 간주되며 탭과 줄 바꿈은 그렇지 않습니다.
Luc

19

최근에 이와 같은 문제가 발생했습니다. 나중에 참조 할 수 있습니다.

import chardet

encoding = chardet.detect(string)
if encoding['encoding'] == 'ascii':
    print 'string is in ascii'

당신이 함께 사용할 수있는 :

string_ascii = string.decode(encoding['encoding']).encode('ascii')

7
물론 이것은 chardet 라이브러리 가 필요합니다 .
StackExchange saddens dancek

1
예, 대부분의 설치에서 기본적으로 chardet을 사용할 수 있습니다
Alvin

7
chardet 은 다음과 같은 특정 확률로 인코딩을 추측합니다. {'confidence': 0.99, 'encoding': 'EUC-JP'}(이 경우에는 완전히 틀 렸습니다)
Suzana

19

Vincent Marchetti는 올바른 아이디어를 str.decode가지고 있지만 Python 3에서는 더 이상 사용되지 않습니다. Python 3에서는 다음을 사용하여 동일한 테스트를 수행 할 수 있습니다 str.encode.

try:
    mystring.encode('ascii')
except UnicodeEncodeError:
    pass  # string is not ascii
else:
    pass  # string is ascii

잡으려는 예외도에서 UnicodeDecodeError로 변경되었습니다 UnicodeEncodeError.


OP의 입력은 바이트 문자열입니다 ( bytes파이썬 3에서는 .encode()메소드 가없는 유형 ). .decode()@Vincent Marchetti의 대답은 정확합니다 .
jfs

@JFSebastian OP는 "파이썬에서 문자열이 ASCII인지 확인하는 방법"을 묻습니다. 바이트 대 유니 코드 문자열을 지정하지 않습니다. 왜 입력을 바이트 스트링이라고합니까?
drs

1
질문 날짜를보십시오 : 'é'당시 바이트 문자열이었습니다.
jfs

1
@JFSebastian, 알았어.이 답변이 오늘 질문 된 것처럼이 질문에 대답한다고 생각하면 여전히 유효하고 도움이된다고 생각합니다. 적은 적은 사람들이 2008 년에 파이썬을 실행하는 것처럼 답을 찾고 여기에 올 것이다
DRS

2
python3에 대한 솔루션을 검색 할 때이 질문을 발견하고 신속하게 질문을 읽으면 이것이 python 2 specfic이라고 의심하지는 않습니다. 그러나이 답변은 정말 도움이되었습니다.
josch

17

질문이 잘못되었습니다. 당신이 보는 오류는 파이썬을 어떻게 빌드했는지에 대한 결과가 아니라 바이트 문자열과 유니 코드 문자열 사이의 혼란의 결과입니다.

바이트 문자열 (예 : 파이썬 구문에서 "foo"또는 "bar")은 8 진수 시퀀스입니다. 0-255 사이의 숫자. 유니 코드 문자열 (예 : u "foo"또는 u'bar ')은 유니 코드 코드 포인트의 시퀀스입니다. 0-1112064의 숫자 그러나 문자 é에 관심이있는 것으로 보입니다 (단말기에서). 단일 문자를 나타내는 멀티 바이트 시퀀스입니다.

대신 다음을 ord(u'é')시도하십시오.

>>> [ord(x) for x in u'é']

"é"가 나타내는 일련의 코드 포인트를 알려줍니다. 그것은 당신에게 줄 수도 있고 [233], 줄 수도 있습니다 [101, 770].

chr()이것을 뒤집는 대신 다음이 있습니다 unichr().

>>> unichr(233)
u'\xe9'

이 문자는 실제로 하나 또는 여러 개의 유니 코드 "코드 포인트"로 표현 될 수 있으며, 그 자체는 그래픽 또는 문자를 나타냅니다. "e는 예음 악센트 (예 : 코드 포인트 233)"또는 "e"(코드 포인트 101)와 "이전 문자의 예음 악센트"(코드 포인트 770)입니다. 따라서이 동일한 문자가 Python 데이터 구조 u'e\u0301'또는 로 표시 될 수 있습니다 u'\u00e9'.

대부분 걱정할 필요는 없지만, 유니 코드 문자열을 반복하는 경우 분해 할 수있는 문자가 아닌 코드 포인트별로 반복이 작동하므로 문제가 될 수 있습니다. 즉, len(u'e\u0301') == 2len(u'\u00e9') == 1. 이것이 당신에게 중요하다면,를 사용하여 작성된 양식과 분해 된 양식을 변환 할 수 있습니다 unicodedata.normalize.

유니 코드 용어집 은 각 특정 용어가 텍스트 표현의 다른 부분을 어떻게 나타내는지를 지적함으로써 이러한 문제 중 일부를 이해하는 데 유용한 안내서가 될 수 있습니다. 이는 많은 프로그래머가 인식하는 것보다 훨씬 복잡합니다.


3
'é'가 반드시 단일 코드 포인트를 나타내는 것은 아닙니다 . 이 수 개의 코드 포인트 (+ 0,065 + U는 U + 0301)를.
jfs

2
각 추상 문자는 항상 단일 코드 포인트로 표시됩니다. 그러나 인코딩 방식에 따라 코드 포인트가 여러 바이트로 인코딩 될 수 있습니다. 즉, 'é'는 UTF-8과 UTF-16에서 2 바이트이고 UTF-32에서 4 바이트이지만 각 경우 여전히 단일 코드 포인트 (U + 00E9)입니다.
Ben Blank

5
@ 벤 빈 : U + 0065과 U + 0301가 있는 코드 포인트 그들이 수있는 'E'대표 U + 00E9으로 나타낼 수있다. 구글 "급성 악센트 결합".
jfs

JF는 U + 0065와 U + 0301을 결합하여 'é'를 형성하는 것이 옳지 만 이것은 가역적 인 펑 티노가 아닙니다. U + 00E9를 얻게됩니다. 에 따르면 위키 피 디아 , 이러한 복합 코드 포인트는 이전 버전과의 호환성을 위해 유용하다
마틴 코네 크니

1
@teehoo-작성된 문자를 나타내는 코드 포인트를 동일한 구성된 문자를 나타내는 코드 포인트 시퀀스로 다시 정규화 할 수 있다는 점에서 가역적 인 기능입니다. 파이썬에서는 다음과 같이 할 수 있습니다 : unicodedata.normalize ( 'NFD', u '\ xe9').
글리프

10

이건 어때?

import string

def isAscii(s):
    for c in s:
        if c not in string.ascii_letters:
            return False
    return True

5
문자열에 문자가 아닌 ASCII 문자가 포함되어 있으면 실패합니다. 줄 바꿈, 공백, 점, 쉼표, 밑줄 및 괄호가 포함 된 코드 예제입니다.
florisla

9

인코딩이 확실하지 않은 문자열을 사용 / 인코딩 / 디코딩하는 방법 (및 해당 문자열의 특수 문자를 이스케이프 / 변환하는 방법)을 결정하는 동안이 질문을 발견했습니다.

첫 번째 단계는 문자열 유형을 확인하는 것이 었습니다. 유형에서 형식에 대한 좋은 데이터를 얻을 수 있다는 것을 알지 못했습니다. 이 답변은 매우 도움이되었고 내 문제의 근원에 도달했습니다.

무례하고 끈질긴 경우

UnicodeDecodeError : 'ascii'코덱이 263 위치에서 바이트 0xc3을 디코딩 할 수 없습니다 : 서 수가 범위 내에 있지 않습니다 (128)

특히 인코딩 할 때 어떤 끔찍한 이유로 이미 유니 코드 인 문자열을 유니 코드 ()하려고 시도하지 마십시오. 아스키 코덱 오류가 발생합니다. ( Python Kitchen 레시피Python 문서 도 참조하십시오. 자습서를 이것이 얼마나 끔찍한 지 이해하십시오.)

결국 나는 내가하고 싶은 것이 이것이라고 결정했다.

escaped_string = unicode(original_string.encode('ascii','xmlcharrefreplace'))

디버깅에 도움이되는 것은 내 파일의 기본 코딩을 utf-8로 설정하는 것입니다 (파이썬 파일의 시작 부분에 넣으십시오).

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

따라서 유니 코드 이스케이프 (u '\ xe0 \ xe9 \ xe7')를 사용하지 않고도 특수 문자 ( 'àéç')를 테스트 할 수 있습니다.

>>> specials='àéç'
>>> specials.decode('latin-1').encode('ascii','xmlcharrefreplace')
'&#224;&#233;&#231;'

4

Python 2.6 (및 Python 3.x)에서 Alexander의 솔루션을 개선하기 위해 헬퍼 모듈 curses.ascii를 사용하고 curses.ascii.isascii () 함수 또는 기타 여러 가지를 사용할 수 있습니다. https://docs.python.org/2.6/ library / curses.ascii.html

from curses import ascii

def isascii(s):
    return all(ascii.isascii(c) for c in s)


2

Posix 표준 [[: ASCII :]] 정의를 허용하는 정규식 라이브러리를 사용할 수 있습니다.


2

str파이썬에서 찌르기 ( -type)는 일련의 바이트입니다. 이 일련의 바이트가 ASCII 문자열을 나타내는 지, ISO-8859-1과 같은 8 비트 문자 세트의 문자열 또는 UTF-8 또는 UTF-16으로 인코딩 된 문자열을 나타내는 지 여부를 알 수있는 방법없습니다. .

그러나 사용 된 인코딩을 알고 있으면 decodestr을 유니 코드 문자열로 만든 다음 정규 표현식 (또는 루프)을 사용하여 관심 범위를 벗어난 문자가 포함되어 있는지 확인할 수 있습니다.


1

@RogerDahl의 답변과 비슷하지만 문자 클래스를 무시 하고 find_all또는 대신 검색을 사용하여 단락하는 것이 더 효율적 match입니다.

>>> import re
>>> re.search('[^\x00-\x7F]', 'Did you catch that \x00?') is not None
False
>>> re.search('[^\x00-\x7F]', 'Did you catch that \xFF?') is not None
True

나는 정규 표현식이 이것에 잘 최적화되어 있다고 생각합니다.


0
import re

def is_ascii(s):
    return bool(re.match(r'[\x00-\x7F]+$', s))

ASCII 빈 문자열을 포함하려면 변경 +*.


-1

코드 충돌을 방지하기 위해 a try-except를 사용하여TypeErrors

>>> ord("¶")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: ord() expected a character, but string of length 2 found

예를 들어

def is_ascii(s):
    try:
        return all(ord(c) < 128 for c in s)
    except TypeError:
        return False

try포장지는 완전히 무의미합니다. 경우 "¶"유니 코드 문자열은 다음 ord("¶")작동합니다, 그것은 (파이썬 2)이 아니라면, for c in s그래서 바이트로 분해됩니다 ord계속 작동합니다.
Ry-

-5

문자열을 ASCII 또는 유니 코드인지 확인하려면 다음을 사용하십시오.

>> print 'test string'.__class__.__name__
str
>>> print u'test string'.__class__.__name__
unicode
>>> 

그런 다음 조건부 블록을 사용하여 함수를 정의하십시오.

def is_ascii(input):
    if input.__class__.__name__ == "str":
        return True
    return False

4
-1 AARRGGHH 이것은 범위 (128, 256)의 ord (c)를 가진 모든 문자를 ASCII로 취급합니다 !!!
John Machin

작동하지 않습니다. 다음을 호출하십시오 is_ascii(u'i am ascii').. 문자와 공백이 ASCII 인 경우에도 False문자열을 강제 로 했기 때문에 여전히 반환 unicode됩니다.
jpmc26
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.