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?
def is_ascii(s):
return all(ord(c) < 128 for c in s)
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"
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
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
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')
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.
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
.
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
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')
'àéç'
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)
Vous pouvez utiliser la bibliothèque d'expressions régulières qui accepte la définition standard [[: ASCII:]] de Posix.
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.
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.
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 *
.
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