web-dev-qa-db-fra.com

Comment vérifier si une chaîne dans Python est en ASCII?

Je veux vérifier si une chaîne est dans ASCII ou non.

Je suis conscient de ord(), cependant, lorsque j'essaie ord('é'), j'ai TypeError: ord() expected a character, but string of length 2 found. J'ai compris que cela est dû à la façon dont j'ai construit Python (comme expliqué dans la documentation de _ (fonction de ord()) ).

Y a-t-il un autre moyen de vérifier?

191
Nico
def is_ascii(s):
    return all(ord(c) < 128 for c in s)
155

Je pense que vous ne posez pas la bonne question ...

Une chaîne dans python n'a aucune propriété correspondant à 'ascii', utf-8 ou à tout autre encodage. La source de votre chaîne (que vous le lisiez à partir d'un fichier, au clavier, etc.) a peut-être codé une chaîne unicode en ascii pour produire votre chaîne, mais c'est là que vous devez rechercher une réponse.

La question que vous pouvez vous poser est peut-être: "Cette chaîne est-elle le résultat du codage d'une chaîne unicode en ascii?" - Ceci, vous pouvez répondre en essayant:

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"
241
Vincent Marchetti

Python 3 voies:

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

Pour vérifier, passez la chaîne de test:

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

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

Nouveau dans Python 3.7 ( bpo32677 )

Plus de contrôles ascii fastidieux/inefficaces sur les chaînes, la nouvelle méthode str/bytes/bytearray intégrée - .isascii() vérifie si les chaînes sont ascii.

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

Nous sommes récemment passés à quelque chose comme ça - pour référence future

import chardet

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

que vous pouvez utiliser avec:

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

Votre question est incorrecte. L'erreur que vous voyez ne résulte pas de la façon dont vous avez construit Python, mais d'une confusion entre les chaînes d'octets et les chaînes Unicode.

Les chaînes d'octets (par exemple "foo" ou "bar" dans la syntaxe python sont des séquences d'octets; numéros de 0-255. Les chaînes Unicode (par exemple, "foo" ou "bar") sont des séquences de points de code Unicode; numéros de 0-1112064. Mais vous semblez être intéressé par le caractère é, qui (dans votre terminal) est une séquence multi-octets qui représente un seul caractère.

Au lieu de ord(u'é'), essayez ceci:

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

Cela vous indique quelle séquence de points de code "é" représente. Cela peut vous donner [233] ou vous donner [101, 770].

Au lieu de chr() pour inverser cela, il y a unichr():

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

Ce caractère peut en réalité être représenté par un ou plusieurs "points de code" unicode, qui représentent eux-mêmes des graphèmes ou des caractères. C'est soit "e avec un accent aigu (c'est-à-dire le point de code 233)", soit "e" (point de code 101), suivi de "un accent aigu sur le caractère précédent" (point de code 770). Ainsi, ce même caractère exact peut être présenté sous la forme de la structure de données Python u'e\u0301'_ ou _u'\u00e9'_.

La plupart du temps, vous ne devriez pas avoir à vous en soucier, mais cela peut devenir un problème si vous effectuez une itération sur une chaîne unicode, car l'itération fonctionne par point de code et non par un caractère décomposable. En d'autres termes, len(u'e\u0301') == 2 et len(u'\u00e9') == 1. Si cela vous importe, vous pouvez convertir des formes composées et décomposées en utilisant unicodedata.normalize .

glossaire Unicode peut être un guide utile pour comprendre certaines de ces questions, en indiquant comment chaque terme spécifique fait référence à une partie différente de la représentation du texte, ce qui est bien plus compliqué que ne le réalisent beaucoup de programmeurs.

17
Glyph

Vincent Marchetti a la bonne idée, mais str.decode est déconseillé dans Python 3. Dans Python 3, vous pouvez effectuer le même test avec str.encode:

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

Notez que l'exception que vous souhaitez intercepter a également changé de UnicodeDecodeError à UnicodeEncodeError.

13
drs

Pourquoi ne pas faire ça?

import string

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

J'ai trouvé cette question en essayant de déterminer comment utiliser/encoder/décoder une chaîne dont je n'étais pas sûr de l'encodage (et comment échapper/convertir des caractères spéciaux dans cette chaîne).

Ma première étape aurait dû être de vérifier le type de la chaîne - je ne m'étais pas rendu compte que je pouvais obtenir de bonnes données sur sa mise en forme à partir de type (s). Cette réponse a été très utile et a permis de mieux cerner mes problèmes.

Si vous obtenez un impoli et persistant

UnicodeDecodeError: le codec 'ascii' ne peut pas décoder l'octet 0xc3 en position 263: l'ordinal n'est pas dans la plage (128)

en particulier lorsque vous ENCODING, assurez-vous que vous n'essayez pas de Unicode () une chaîne déjà IS Unicode - pour une raison quelconque, vous obtenez des erreurs de codec Ascii. (Voir aussi les didacticiels recettes de cuisine Python et les didacticiels docs Python pour une meilleure compréhension de la gravité de la situation.)

Finalement, j'ai déterminé que ce que je voulais faire était ceci:

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

Le débogage a également été utile en définissant le code par défaut dans mon fichier sur utf-8 (placez-le au début de votre fichier python):

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

Cela vous permet de tester des caractères spéciaux ('àéç') sans avoir à utiliser leurs échappements Unicode (u '\ xe0\xe9\xe7').

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

Pour améliorer la solution d'Alexander à partir de la Python 2.6 (et dans Python 3.x), vous pouvez utiliser le module auxiliaire curses.ascii et utiliser la fonction curses.ascii.isascii () ou toute autre fonction: 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)
4

Vous pouvez utiliser la bibliothèque d'expressions régulières qui accepte la définition standard [[: ASCII:]] de Posix.

2
Steve Moyer

Une piqûre (str- type) dans Python est une série d'octets. Il y a aucun moyen de simplement dire en regardant la chaîne si cette série d'octets représente une chaîne ascii, une chaîne dans un jeu de caractères à 8 bits comme ISO-8859-1 ou une chaîne encodée avec UTF- 8 ou UTF-16 ou autre.

Cependant, si vous connaissez le codage utilisé, vous pouvez alors decode la chaîne dans une chaîne unicode, puis utiliser une expression régulière (ou une boucle) pour vérifier si elle contient des caractères extérieurs à la plage qui vous préoccupe.

2
JacquesB

Comme @ RogerDahl réponse mais il est plus efficace de court-circuiter en annulant la classe de caractères et en utilisant la recherche au lieu de find_all ou 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

J'imagine qu'une expression régulière est bien optimisée pour cela.

1
hobs
import re

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

Pour inclure une chaîne vide en tant qu'ASCII, remplacez le + par *.

0
Roger Dahl

Pour éviter que votre code ne plante, vous pouvez peut-être utiliser un try-except pour intercepter TypeErrors

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

Par exemple

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