Jak sprawdzić, czy ciąg znaków w Pythonie jest w ASCII?

Chcę sprawdzić, czy łańcuch jest w ASCII, czy nie.

Jestem świadomy ord(), jednak kiedy próbuję ord('é'), mam TypeError: ord() expected a character, but string of length 2 found. Rozumiem, że jest to spowodowane przez sposób, w jaki zbudowałem Pythona (jak wyjaśniono w ord()'s dokumentacja ).

Czy jest inny sposób na sprawdzenie?
Author: Amir, 2008-10-13

16 answers

def is_ascii(s):
    return all(ord(c) < 128 for c in s)
 135
Author: Alexander Kojevnikov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-13 00:30:43

Myślę, że nie zadajesz właściwego pytania ... ]}

Ciąg znaków w Pythonie nie ma właściwości odpowiadającej 'ascii', utf-8, ani żadnemu innemu kodowaniu. Źródło twojego ciągu (niezależnie od tego, czy czytasz go z pliku, wprowadzasz z klawiatury, itp.) może zakodował ciąg unicode w ascii, aby wytworzyć Twój ciąg, ale tam musisz znaleźć odpowiedź.

Być może pytanie, które możesz zadać, brzmi: "Czy ten ciąg jest wynikiem kodowania ciągu unicode w ascii?"--To możesz odpowiedź próbując:

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"
 225
Author: Vincent Marchetti,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-13 00:30:32

Python 3 way:

isascii = lambda s: len(s) == len(s.encode())
 120
Author: far,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-19 13:05:58

Wpadłem na coś takiego niedawno-dla przyszłych odniesień

import chardet

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

Które można wykorzystać z:

string_ascii = string.decode(encoding['encoding']).encode('ascii')
 18
Author: Alvin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-08 20:47:22

Twoje pytanie jest niepoprawne; błąd, który widzisz, nie wynika z tego, jak zbudowałeś Pythona, ale z pomyłki między łańcuchami bajtów i łańcuchami unicode.

Ciągi bajtów (np. "foo" lub " bar " w składni Pythona) są sekwencjami oktetów; liczby od 0-255. Ciągi znaków Unicode (np. u"foo" lub u' bar') są sekwencjami punktów kodu unicode; liczby od 0-1112064. Ale wydaje się, że interesuje Cię znak é, który (w terminalu) jest sekwencją wielobajtową, która reprezentuje pojedynczy charakter.

Zamiast ord(u'é'), Spróbuj tego:

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

To mówi, który ciąg punktów kodu" é " reprezentuje. Może dać wam [233], albo może dać wam [101, 770].

Zamiast chr() aby to odwrócić, jest unichr():

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

Ten znak może być reprezentowany jako jeden lub wiele punktów kodu unicode, które same reprezentują grafemy lub znaki. Jest to albo " e z akcentem ostrym (tj. kod pkt 233)", albo "e" (Kod punkt 101), po którym następuje "akcent ostry na poprzedni znak "(punkt kodowy 770). Tak więc ten sam znak może być przedstawiony jako struktura danych Pythona u'e\u0301' lub u'\u00e9'.

Przez większość czasu nie powinieneś się tym przejmować, ale może to stać się problemem, jeśli iterację wykonujesz nad ciągiem unicode, ponieważ iteracja działa przez punkt kodu, a nie przez rozkładalny znak. Innymi słowy, len(u'e\u0301') == 2 i len(u'\u00e9') == 1. Jeśli ma to dla Ciebie znaczenie, możesz konwertować między formami złożonymi i rozłożonymi przez za pomocą unicodedata.normalize.

Słowniczek Unicode może być pomocnym przewodnikiem w zrozumieniu niektórych z tych zagadnień, wskazując, w jaki sposób każdy konkretny termin odnosi się do innej części reprezentacji tekstu, która jest znacznie bardziej skomplikowana niż wielu programistów zdaje sobie sprawę.

 17
Author: Glyph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-08 02:10:02

Co ty na to?

import string

def isAscii(s):
    for c in s:
        if c not in string.ascii_letters:
            return False
    return True
 10
Author: miya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-13 16:38:25

Vincent Marchetti ma słuszny pomysł, ale [1]} został wycofany w Pythonie 3. W Pythonie 3 możesz wykonać ten sam test za pomocą str.encode:

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

Uwaga wyjątek, który chcesz złapać również zmienił się z UnicodeDecodeError na UnicodeEncodeError.

 9
Author: drs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-02 15:45:04

Znalazłem to pytanie podczas próby określenia, jak używać/kodować / dekodować ciąg znaków, którego kodowania nie byłem pewien (i jak uciec / przekonwertować znaki specjalne w tym łańcuchu).

Moim pierwszym krokiem powinno być sprawdzenie typu łańcucha-nie zdawałem sobie sprawy, że mogę uzyskać dobre dane o jego formatowaniu z type(S). Ta odpowiedź była bardzo pomocna i dotarła do prawdziwego źródła moich problemów.

Jeśli jesteś niegrzeczny i uparty

UnicodeDecodeError: kodek' ascii ' nie może dekodować bajtu 0xc3 w pozycji 263: ordinal not in range(128)

Szczególnie podczas kodowania, upewnij się, że nie próbujesz Unicode() ciąg znaków, który już jest unicode - z jakiegoś strasznego powodu, dostajesz błędy kodeka ascii. (Zobacz także przepis na kuchnię Pythona {[7] } i samouczki Python docs , aby lepiej zrozumieć, jak straszne może to być.)

W końcu stwierdziłem, że to, co chcę zrobić, to to:

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

Pomocne w debugowaniu było również ustawienie domyślnego kodowania w moim pliku na utf-8 (Umieść to na początku pliku Pythona):

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

, który pozwala na testowanie znaków specjalnych ('àéç') bez konieczności używania ich znaków specjalnych unicode (u '\xe0\xe9\xe7').

>>> specials='àéç'
>>> specials.decode('latin-1').encode('ascii','xmlcharrefreplace')
'&#224;&#233;&#231;'
 8
Author: Max P Magee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:55:10

Aby poprawić rozwiązanie Alexandra z Pythona 2.6 (oraz w Pythonie 3.x) możesz użyć klątwy modułu pomocniczego.ascii i używać przekleństw.ascii.funkcja isascii() lub różne inne: 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
Author: Sergey Nevmerzhitsky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-22 09:17:16

Możesz użyć biblioteki wyrażeń regularnych, która akceptuje standard Posix [[: ASCII:]].

 2
Author: Steve Moyer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-13 00:18:25

Sting (str-type) w Pythonie jest serią bajtów. Nie ma sposobu, aby powiedzieć po prostu patrząc na łańcuch, czy ta seria bajtów reprezentuje łańcuch ascii, łańcuch w 8-bitowym kodowaniu, takim jak ISO-8859-1 lub łańcuch zakodowany za pomocą UTF-8 lub UTF-16, czy cokolwiek innego.

Jeśli jednak znasz używane kodowanie, możesz decode str do ciągu znaków unicode, a następnie użyć wyrażenia regularnego (lub pętli), aby sprawdzić, czy zawiera znaki spoza zakresu, w którym jesteś zaniepokojony.

 2
Author: JacquesB,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-14 08:10:06

Nowy w Pythonie 3.7 (bpo32677 )

Koniec z męczącym / nieefektywnym sprawdzaniem znaków ascii, nowe wbudowane str/bytes/bytearray metoda - .isascii() sprawdzi, czy ciągi znaków są ascii.

print("is this ascii?".isascii())
# True
 2
Author: abccd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-02 18:32:22

Aby zapobiec awariom kodu, możesz użyć try-except, aby złapać TypeErrors

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

Na przykład

def is_ascii(s):
    try:
        return all(ord(c) < 128 for c in s)
    except TypeError:
        return False
 0
Author: Sebastian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-07 21:16:00
import re

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

Aby dodać pusty łańcuch jako ASCII, zmień + na *.

 0
Author: Roger Dahl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-30 14:51:52

Podobnie jak odpowiedź @RogerDahl , ale bardziej efektywne jest zwarcie poprzez negację klasy znaków i użycie wyszukiwania zamiast find_all lub 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

Wyobrażam sobie, że wyrażenie regularne jest do tego dobrze zoptymalizowane.

 0
Author: hobs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:24

Używam poniższego, aby określić, czy łańcuch jest ascii lub unicode:

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

Następnie wystarczy użyć warunkowego bloku do zdefiniowania funkcji:

def is_ascii(input):
    if input.__class__.__name__ == "str":
        return True
    return False
 -4
Author: user397587,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-21 06:34:56