Pythonの文字列がASCIIかどうかを確認するにはどうすればよいですか?


211

文字列がASCIIかどうかを確認したい。

気づいていますが、やってord()みるord('é')とわかりますTypeError: ord() expected a character, but string of length 2 found。Pythonのビルド方法が原因であることがわかりました(ord()のドキュメントで説明されています)。

チェックする別の方法はありますか?


文字列エンコーディングは、Python 2とPython 3でかなり異なります。そのため、どのバージョンを対象にしているのかを知っておくとよいでしょう。
florisla 2017

回答:


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

95
無意味に非効率的です。Vincent Marchettiによって提案されているように、s.decode( 'ascii')を試してUnicodeDecodeErrorをキャッチする方がはるかに優れています。
ddaa 2008年

20
非効率的ではありません。all()は無効なバイトに遭遇するとすぐに短絡してFalseを返します。
ジョンミリキン、

10
非効率的かどうかにかかわらず、よりパイソン的な方法はtry / exceptです。
Jeremy Cantrell、

43
try / exceptに比べて非効率的です。ここで、ループはインタープリター内にあります。try / exceptフォームでは、ループはstr.decode( 'ascii')によって呼び出されるCコーデック実装にあります。そして、私は同意します。try/ exceptフォームもよりPythonicです。
ddaa 2008年

25
@JohnMachinがord(c) < 128無限よりも読みやすく、直感的であるc <= "\x7F"
スレーターVictoroff

252

あなたは正しい質問をしていないと思います-

Pythonの文字列には、「ascii」、utf-8、またはその他のエンコーディングに対応するプロパティはありません。文字列のソース(ファイルから読み取るか、キーボードから入力するかなど)は、ASCIIでUnicode文字列をエンコードして文字列を生成している可能性がありますが、ここで答えを得る必要があります。

おそらくあなたが尋ねることができる質問は次のとおりです:「この文字列は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
エンコードを使用する方が良いです。Python3のデコードメソッドは文字列ではないため、エンコード/デコードの違い
Jet Guo

@Sri:エンコードされていない文字列(strPython 2、bytesPython 3)で使用しているためです。
dotancohen 2013

Python 2では、このソリューションはUnicode文字列に対してのみ機能します。strISOエンコーディングのA は、最初にUnicodeにエンコードする必要があります。答えはこれに入るはずです。
アレクシス2014年

@JetGuo:s.decode('ascii') if isinstance(s, bytes) else s.encode('ascii')Python 3では、入力タイプに応じて両方を使用する必要があります。OPの入力はバイト文字列'é'(Python 2構文、Python 3はその時点ではリリースされていません)であり、したがって.decode()正しいです。
jfs

2
@alexis:間違っています。strPython 2ではバイト文字列です。.decode('ascii')すべてのバイトがASCII範囲内にあるかどうかを調べるために使用するのは正しいことです。
jfs

153

Python 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
これは、Unicode文字列内の非ASCII文字を検出するための素晴らしいトリックです。Python3では、ほとんどすべての文字列です。ASCII文字は1バイトのみを使用してエンコードできるため、ASCII文字の長さはバイトにエンコードされた後のサイズに忠実になります。一方、他の非ASCII文字は2バイトまたは3バイトにエンコードされるため、サイズが大きくなります。
Devy

@farまでの最良の回答ですが、…や—のような一部の文字はasciiのように見える場合があるため、これを使用して英語のテキストを検出する場合は、チェックする前にそのような文字を置き換えます
Christophe Roussy

1
しかし、Python2ではUnicodeEncodeErrorがスローされます。Py2とPy3の両方の解決策を見つけよう
alvas

2
ラムダの使用に不慣れな方のために(最初にこの回答に出会ったときのように)isascii、文字列を渡す関数になりました:isascii('somestring')== Trueおよびisascii('àéç')==False
rabidang3ls

8
これは単なる無駄です。文字列をUTF-8でエンコードし、他のバイト文字列全体を作成します。真のPython 3の方法はtry: s.encode('ascii'); return True except UnicodeEncodeError: return False(上記と同様ですが、文字列はPython 3のUnicodeであるため、エンコーディングです)。サロゲートがある場合、この回答はPython 3でもエラーを発生させます(たとえばisascii('\uD800')、を返すのではなくエラーを発生させますFalse
Artyer

71

Python 3.7の新機能(bpo32677

文字列の面倒/非効率なasciiチェックが不要になり、新しい組み込みのstr/ bytes/ bytearrayメソッド- .isascii()文字列がasciiかどうかをチェックします。

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

これはトップに値する!
サレク

"\x03".isascii()も真です。ドキュメントでは、これはすべての文字がコードポイント128(0〜127)未満であることを確認するだけであると述べています。制御文字も避けたい場合は、次のものが必要ですtext.isascii() and text.isprintable()isprintable¿のような文字は(正しく)印刷可能であると見なされるため、単独で使用するだけでも十分ではありませんが、ASCII印刷可能セクション内にはないため、両方が必要な場合は両方をチェックする必要があります。さらに別の落とし穴:スペースは印刷可能と見なされますが、タブと改行はそうではありません。
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 '30 / 10/30

1
はい、ただしchardetはデフォルトでほとんどのインストールで利用可能です
Alvin

7
chardetは、次のような一定の確率でエンコーディングを推測するだけです{'confidence': 0.99, 'encoding': 'EUC-JP'}(この場合は完全に間違っていました)
Suzana

19

Vincent Marchettiは正しい考えをstr.decode持っていますが、Python 3では非推奨になりました。Python3では、次のコマンドで同じテストを行うことができますstr.encode

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

キャッチする例外もからUnicodeDecodeErrorに変更されましたUnicodeEncodeError


OPの入力はバイト文字列(メソッドのbytesないPython 3の型.encode())です。.decode()@Vincent Marchettiの答えは正しいです。
jfs

@JFSebastian OPは、「Pythonの文字列がASCIIであるかどうかを確認する方法は?」そして、バイト対ユニコード文字列を指定しません。なぜあなたは彼/彼女の入力がバイト文字列であると言うのですか?
DRS

1
質問の日付を見てください'é'。当時はバイト文字列でした。
jfs

1
@JFSebastian、そうですね、この質問への回答が今日の質問のようであるかのように考えれば、この質問はまだ有効であり、役立つと思います。2008年にPythonを実行しているかのように、回答を求めてここに来る人は少なくなります
drs

2
私がpython3の解決策を探していたときにこの質問を見つけましたが、すぐに質問を読んでも、これがpython 2固有のものであるとは思われませんでした。しかし、この回答は本当に役に立ちました-賛成票です!
josch

17

あなたの質問は間違っています。表示されるエラーは、Pythonの構築方法の結果ではなく、バイト文字列とUnicode文字列の混同によるものです。

バイト文字列(たとえば、Python構文では「foo」または「bar」)はオクテットのシーケンスです。0〜255の数値。Unicode文字列(たとえば、u "foo"またはu'bar ')は、Unicodeコードポイントのシーケンスです。0〜1112064の数値。しかし、あなたは(端末では)単一の文字を表すマルチバイトシーケンスである文字éに興味があるようです。

の代わりにord(u'é')、これを試してください:

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

これにより、「é」が表すコードポイントのシーケンスがわかります。それはあなたに[233]を与えるかもしれませんし、それはあなたに[101、770]を与えるかもしれません。

代わりにchr()これを逆に、そこにありますunichr()

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

この文字は、実際には、書記素または文字のいずれかを表す単一または複数のUnicode「コードポイント」のいずれかで表されます。これは、「eの鋭アクセント(つまり、コードポイント233)」または「e」(コードポイント101)の後に「前の文字の鋭アクセント」(コードポイント770)が続きます。したがって、このまったく同じ文字は、Pythonデータ構造u'e\u0301'またはとして表示される場合がありますu'\u00e9'

ほとんどの場合、これを気にする必要はありませんが、Unicode文字列を反復処理する場合は、分解が可能な文字ではなくコードポイントによって反復が機能するため、問題になる可能性があります。言い換えれば、len(u'e\u0301') == 2そしてlen(u'\u00e9') == 1。これが重要な場合は、を使用して、合成フォームと分解フォームを変換できますunicodedata.normalize

Unicode用語集は、特定の各用語がテキスト表現の異なる部分をどのように参照するかを指摘することにより、これらの問題のいくつかを理解するのに役立つガイドになる可能性があり、多くのプログラマーが理解するよりもはるかに複雑です。


3
「é」は必ずしも単一のコードポイントを表すわけでありませ。それは可能性が2つのコード・ポイント(U + 0065 + U + 0301)。
jfs

2
各抽象文字は常に単一のコードポイントで表されます。ただし、コードスキームによっては、コードポイントが複数のバイトにエンコードされる場合があります。つまり、 'é'はUTF-8とUTF-16では2バイト、UTF-32では4バイトですが、いずれの場合も1つのコードポイント(U + 00E9)です。
Ben Blank

5
@Benブランク:U + 0065とU + 0301 であるコードポイント及びそれらが行うことができ「E」表し、また U + 00E9によって表すことがあります。グーグル「鋭いアクセントを組み合わせる」。
jfs

JFはU + 0065とU + 0301を組み合わせて「é」を形成するのは正しいですが、これは可逆的な機能ではありません。U + 00E9を取得します。ウィキペディアによれば、これらの複合コードポイントは、下位互換性のために有用です
Martin Konecny

1
@teehoo-合成文字を表すコードポイントを、同じ合成文字を表す一連のコードポイントに再正規化できるという意味で、これは可逆関数です。Pythonでは、次のようにできます: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 2017

9

エンコーディングがわからない文字列を使用/エンコード/デコードする方法(およびその文字列内の特殊文字をエスケープ/変換する方法)を決定しようとしたときに、この質問を見つけました。

私の最初のステップは、文字列のタイプをチェックすることでした。タイプからフォーマットに関する適切なデータを取得できることに気づきませんでした。 この回答は非常に役に立ち、私の問題の根本原因になりました。

あなたが失礼でしつこくなっているなら

UnicodeDecodeError: 'ascii'コーデックは、263桁目のバイト0xc3をデコードできません:序数が範囲(128)にありません

特にエンコードする場合は、すでにUnicodeになっている文字列をunicode()しようとしないようにしてください。なんらかの理由で、ASCIIコーデックエラーが発生します。(これがどれほどひどいのかをよりよく理解するには、Python KitchenレシピPython docs tutorials も参照してください。)

結局、私がやりたかったのはこれだと判断しました。

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

デバッグに役立つのは、ファイルのデフォルトのコーディングをutf-8に設定することです(これをpythonファイルの先頭に置きます)。

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

これにより、Unicodeエスケープ(u '\ xe0 \ xe9 \ xe7')を使用せずに特殊文字( 'àéç')をテストできます。

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

4

Python 2.6(およびPython 3.x)からのA​​lexanderのソリューションを改善するには、ヘルパーモジュール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

strPythonのスティング(-type)は一連のバイトです。文字列を見ただけでは、この一連のバイトがASCII文字列、ISO-8859-1のような8ビット文字セットの文字列、またはUTF-8またはUTF-16でエンコードされた文字列を表すかどうかを判断する方法はありません。

ただし、使用されているエンコーディングがわかっている場合はdecode、strをUnicode文字列に変換し、正規表現(またはループ)を使用して、問題の範囲外の文字が含まれているかどうかを確認できます。


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

クラッシュからあなたのコードを防ぐために、あなたは多分使用したい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ラッパーは完全に無意味です。"¶"がUnicode文字列の場合はord("¶")機能し、そうでない場合(Python 2)はfor c in sそれをバイトに分解するためord、機能し続けます。
Ry-

-5

以下を使用して、文字列がASCIIまたはUnicodeであるかどうかを判断します。

>> 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、2010

動作しません。次を呼び出してみてください:is_ascii(u'i am ascii')。文字とスペースは間違いなくASCIIですがFalse、文字列をに強制したため、これはまだ返されますunicode
jpmc26 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.