Как проверить, находится ли строка в Python в ASCII?

Я хочу проверить, находится ли строка в ASCII или нет.

Я знаю ord(), однако, когда я пробую ord('é'), у меня есть TypeError: ord() expected a character, but string of length 2 found. Я понял, что это вызвано тем, как я построил Python (как описано в Документация ord()).

Есть другой способ проверить?

Кодировка строк в Python 2 и Python 3 немного отличается, поэтому было бы неплохо знать, на какую версию вы нацеливаетесь.

florisla 13.07.2017 12:46

@florisla На основе ошибки ord('é'), OP использует Python 2.

wjandrea 12.07.2020 21:16
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
228
2
228 729
16
Перейти к ответу Данный вопрос помечен как решенный

Ответы 16

Вы можете использовать библиотеку регулярных выражений, которая принимает стандартное определение Posix [[: ASCII:]].

Я думаю, вы задаете неправильный вопрос -

Строка в python не имеет свойства, соответствующего ascii, utf-8 или любой другой кодировке. Источник вашей строки (независимо от того, читаете ли вы ее из файла, вводите с клавиатуры и т. д.), Возможно, закодировал строку Unicode в ascii для создания вашей строки, но вам нужно найти ответ.

Возможно, вы спросите: «Является ли эта строка результатом кодирования строки Unicode в 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"

использовать кодировку лучше, потому что строка не имеет метода декодирования в python 3, см. какая разница между кодированием / декодированием? (Python 2.x)

Jet Guo 08.05.2011 19:21

@Sri: Это потому, что вы используете его в незакодированной строке (str в Python 2, bytes в Python 3).

dotancohen 29.12.2013 11:15

В Python 2 это решение работает только для строки юникод. str в любой кодировке ISO необходимо сначала закодировать в Unicode. Ответ должен заключаться в этом.

alexis 07.10.2014 13:49

@JetGuo: вы должны использовать оба в зависимости от типа ввода: s.decode('ascii') if isinstance(s, bytes) else s.encode('ascii') в Python 3. Ввод OP представляет собой байтовую строку 'é' (синтаксис Python 2, Python 3 не был выпущен в то время), поэтому .decode() является правильным.

jfs 04.09.2015 13:36

@Sri: вы передали строку Unicode вместо строки байтов. Python 2 пытается неявно кодировать с помощью sys.getdefaultencoding() ('ascii'). Если ваш ввод - Unicode; вместо этого явно используйте .encode('ascii', 'strict').

jfs 04.09.2015 13:36

@alexis: неправильно. str на Python 2 - это байтовая строка. Правильно использовать .decode('ascii'), чтобы узнать, все ли байты находятся в диапазоне ascii.

jfs 04.09.2015 13:36

Вопрос @JetGuo OP касался Python 2. Использование mystring.encode('ascii') здесь на самом деле сначала попытается декодировать строку, используя системное значение по умолчанию, чтобы создать строку Unicode, а затем перекодировать эту строку как указанную кодировку, что является плохим способом сделать это. .

augurar 25.01.2017 08:16
Ответ принят как подходящий

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

Бессмысленно неэффективно. Гораздо лучше попробовать s.decode ('ascii') и поймать UnicodeDecodeError, как предложил Винсент Маркетти.

ddaa 13.10.2008 22:48

Это не неэффективно. all () выполнит короткое замыкание и вернет False, как только обнаружит недопустимый байт.

John Millikin 14.10.2008 00:03

Неэффективный или нет, более питонический метод - это try / except.

Jeremy Cantrell 14.10.2008 18:38

Это неэффективно по сравнению с try / except. Здесь цикл находится в интерпретаторе. В форме try / except цикл находится в реализации кодека C, вызываемом str.decode ('ascii'). И я согласен, форма try / except тоже более питоническая.

ddaa 16.10.2008 21:55

-1 Не только цикл по коду Python вместо кода C, но также есть вызов функции Python ord(c) - UGLY - по крайней мере, вместо этого используется c <= "\x7F".

John Machin 21.07.2010 11:54

@JohnMachin ord(c) < 128 бесконечно более читабелен и интуитивно понятен, чем c <= "\x7F"

Slater Victoroff 28.06.2013 20:04

«Неэффективность» зависит от длины строк и вероятности данных ASCII; для коротких строк, не являющихся ASCII, эта функция может быть быстрее, чем установка блока try / except и обработка исключения.

Alex Dupuy 02.07.2013 23:27

Использование блока try-catch - это не питонизм, а злоупотребление.

Fermat's Little Student 12.12.2017 08:09

Кажется, люди без ума от питонизма, чем от здравомыслия. Этот ответ для меня намного проще, чем попытка, за исключением того, что я хочу использовать его в понимании списка. Я хочу фильтровать большой текстовый корпус, выкидывая все слова, а не ascii. Как бы вы сделали это с помощью try..except?

Binu Jasim 30.05.2018 13:00

@BinuJasim Вы по-прежнему можете фильтровать с помощью метода try / catch в понимании списка, если вы заключите его в функцию, которая возвращает True или False в зависимости от того, было ли создано исключение. Тем не менее, ни для одного из этих методов не годится; Помимо эффективности, я думаю, что оба метода хороши, если они существуют как функция с соответствующим именем.

user193130 02.10.2019 23:43

Как насчет этого?

import string

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

Это не сработает, если строка содержит символы ASCII, которые не являются буквами. Для вас примеры кода, которые включают новую строку, пробел, точку, запятую, подчеркивание и круглые скобки.

florisla 13.07.2017 12:52

Ваш вопрос неверен; ошибка, которую вы видите, не является результатом того, как вы построили python, а путаницей между байтовыми строками и строками Unicode.

Строки байтов (например, «foo» или «bar» в синтаксисе Python) представляют собой последовательности октетов; числа от 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 может быть полезным руководством для понимания некоторых из этих проблем, указывая, как каждый конкретный термин относится к разной части представления текста, что намного сложнее, чем думают многие программисты.

«é» действительно ли нет представляет одну кодовую точку. Это могут быть кодовые точки два (U + 0065 + U + 0301).

jfs 24.01.2009 06:17

Каждый абстрактный символ представляет собой всегда, представленный одной кодовой точкой. Однако кодовые точки могут быть закодированы в несколько байтов, в зависимости от схемы кодирования. т.е. 'é' - это два байта в UTF-8 и UTF-16 и четыре байта в UTF-32, но в каждом случае это по-прежнему одна кодовая точка - U + 00E9.

Ben Blank 24.01.2009 06:43

@Ben Blank: кодовые точки U + 0065 и U + 0301 являются, и они делать представляют собой 'é', которое может быть представлено также как U + 00E9. Гугл «сочетание острого акцента».

jfs 24.01.2009 10:48

J.F. прав, объединив U + 0065 и U + 0301 для образования «é», но это не обратимая функция. Вы получите U + 00E9. Согласно википедия, эти составные кодовые точки полезны для обратной совместимости.

Martin Konecny 07.07.2011 20:07

@teehoo - это обратимая функция в том смысле, что вы можете повторно нормализовать кодовую точку, представляющую составной символ, в последовательность кодовых точек, представляющих тот же составной символ. В Python это можно сделать так: unicodedata.normalize ('NFD', u '\ xe9').

Glyph 08.07.2011 05:52

Я обновил ответ, чтобы попытаться учесть некоторые из этих отзывов, а также изменения, внесенные в вопрос.

Glyph 08.07.2011 06:12

Жало (типа str) в Python - это серия байтов. Существует ни за что, чтобы узнать, просто взглянув на строку, представляет ли эта серия байтов строку ascii, строку в 8-битной кодировке, такой как ISO-8859-1, или строку, закодированную с помощью UTF-8 или UTF-16 или что-то еще.

Однако, если вы знаете используемую кодировку, вы можете decode преобразовать str в строку Unicode, а затем использовать регулярное выражение (или цикл), чтобы проверить, содержит ли оно символы за пределами диапазона, который вас беспокоит.

Я использую следующее, чтобы определить, является ли строка 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

-1 AARRGGHH это обрабатывает все символы с ord (c) в диапазоне (128, 256) как ASCII !!!

John Machin 21.07.2010 11:56

Не работает. Попробуйте вызвать по следующему номеру: is_ascii(u'i am ascii'). Несмотря на то, что буквы и пробелы определенно являются ASCII, это все равно возвращает False, потому что мы заставили строку быть unicode.

jpmc26 19.02.2014 23:30

Недавно наткнулся на что-то подобное - на будущее.

import chardet

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

который можно использовать с:

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

Конечно, для этого нужна библиотека Chardet.

StackExchange saddens dancek 30.10.2011 15:30

да, хотя chardet доступен по умолчанию в большинстве установок

Alvin 08.09.2012 03:17
Chardet only guesses the encoding with a certain probability like this: {'confidence': 0.99, 'encoding': 'EUC-JP'} (which in this case was completely wrong)
Suzana 07.03.2013 18:09

Я нашел этот вопрос, пытаясь определить, как использовать / кодировать / декодировать строку, в кодировке которой я не был уверен (и как избежать / преобразовать специальные символы в этой строке).

Моим первым шагом должна была быть проверка типа строки - я не понимал, что могу получить хорошие данные о ее форматировании из типа (ов). Этот ответ был очень полезным и помог мне понять суть моих проблем.

Если вы становитесь грубым и настойчивым

UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 263: ordinal not in range(128)

особенно когда вы КОДИРУЕТЕ, убедитесь, что вы не пытаетесь использовать unicode () для строки, которая уже ЕСТЬ unicode - по какой-то ужасной причине вы получаете ошибки кодека ascii. (См. Также руководства по Рецепт кухни Python и Документы Python, чтобы лучше понять, насколько это может быть ужасно.)

В конце концов я решил, что хочу сделать следующее:

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

Также при отладке было полезно установить кодировку по умолчанию в моем файле на utf-8 (поместите это в начало вашего файла python):

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

Это позволяет вам тестировать специальные символы ('àéç') без необходимости использовать их escape-символы в Юникоде (u '\ xe0 \ xe9 \ xe7').

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

Чтобы предотвратить сбой вашего кода, вы, возможно, захотите использовать 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- 19.10.2019 10:07

В Python 3 мы можем закодировать строку как UTF-8, а затем проверить, остается ли длина такой же. Если да, то исходной строкой является ASCII.

def isascii(s):
    """Check if the characters in string s are in ASCII, U+0-U+7F."""
    return len(s) == len(s.encode())

Для проверки передайте тестовую строку:

>>> isascii("♥O◘♦♥O◘♦")
False
>>> isascii("Python")
True

Это приятный маленький трюк для обнаружения символов, отличных от ascii, в строках Unicode, которые в python3 представляют собой практически все строки. Поскольку символы ascii можно кодировать, используя только 1 байт, любая длина символов ascii будет соответствовать своему размеру после кодирования в байты; тогда как другие символы, отличные от ascii, будут закодированы в 2 байта или 3 байта соответственно, что увеличит их размер.

Devy 04.03.2016 20:13

По @far лучший ответ, но не то, что некоторые символы вроде ... и - могут выглядеть как ascii, поэтому, если вы хотите использовать это для обнаружения английского текста, замените такие символы перед проверкой

Christophe Roussy 28.07.2016 15:25

Но в Python2 он выдаст UnicodeEncodeError. Надо найти решение как для Py2, так и для Py3

alvas 25.01.2017 09:43

Это просто расточительно. Он кодирует строку в UTF-8, создавая целую другую строку байтов. Истинный способ Python 3 - try: s.encode('ascii'); return Trueexcept UnicodeEncodeError: return False (как и выше, но с кодировкой, поскольку строки являются Unicode в Python 3). Этот ответ также вызывает ошибку в Python 3, когда у вас есть суррогаты (например, isascii('\uD800') вызывает ошибку вместо возврата False)

Artyer 26.07.2017 16:36

Это выглядит довольно красиво, но мне интересно, так же ли он эффективен, как all, при обработке длинной строки.

Endle_Zhenbo 20.04.2018 00:02

@ChristopheRoussy - эти символы (кодовые точки) будут закодированы в несколько байтов, поэтому то, что вы говорите, не имеет смысла.

Shuzheng 23.02.2021 15:58

Чтобы улучшить решение Александра из Python 2.6 (и в Python 3.x), вы можете использовать вспомогательный модуль 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)

это работает, но будьте осторожны известны проблемы с функциями классификации символов из curses.ascii

jfs 02.10.2015 11:44

Винсент Маркетти придерживается правильной идеи, но 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 в Python 3, который не имеет метода .encode()). .decode() в ответе @Vincent Marchetti верен.

jfs 04.09.2015 13:43

@ J.F.Sebastian OP спрашивает: "Как проверить, находится ли строка в Python в ASCII?" и не указывает байты и строки в Юникоде. Почему вы говорите, что его / ее ввод - это байтовая строка?

drs 04.09.2015 16:07

посмотрите на дату вопроса: 'é' в то время был байтовой строкой.

jfs 04.09.2015 16:19

@ J.F.Sebastian, хорошо, учитывая, что этот ответ отвечает на этот вопрос, как если бы он был задан сегодня, я думаю, что он по-прежнему актуален и полезен. Все меньше и меньше людей будут приходить сюда в поисках ответов, как если бы они работали на Python в 2008 году.

drs 04.09.2015 20:22

OP не стал бы задавать этот вопрос сегодня: ord('é') == 1 на Python 3 (в целом может быть> 1, но это не связано с тем, что строка находится в диапазоне ascii или нет). В любом случае, если не указано, является ли входная строка Unicode; оба могут использоваться: s.decode('ascii') if isinstance(s, bytes) else s.encode('ascii')

jfs 04.09.2015 21:48

Я нашел этот вопрос, когда искал решение для python3, и быстрое прочтение вопроса не заставило меня заподозрить, что это специфика python 2. Но этот ответ был действительно полезным - голосование за!

josch 11.10.2015 21:51

Мне этот ответ нравится намного больше, поскольку я использую Python3, в котором все строки по определению являются строками Unicode, в результате чего будет вызывать метод .encode(). Этот ответ кажется более питоническим, чем другой ответ о сравнении длины символа до и после кодирования.

Devy 04.03.2016 20:17

Это решение, совместимое с py2 и py3, которое я искал!

ebeezer 15.08.2019 03:24

import re

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

Чтобы включить пустую строку как ASCII, измените + на *.

Подобно отвечать @ 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

Я полагаю, что регулярное выражение хорошо оптимизировано для этого.

Новое в 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 printable, поэтому вам нужно проверить оба, если вы хотите и то, и другое. Еще одна проблема: пробелы считаются печатаемыми, а табуляции и новые строки - нет.

Luc 15.04.2020 18:47

@Luc Полезно знать, но ASCII включает управляющие символы. Избегать их - другая тема.

wjandrea 13.07.2020 20:08

@wjandrea Да, очевидно, но то, что 0x03 умещается в 7 битах, не означает, что это то, что большинство людей захотят проверять, когда найдут эту страницу в своих результатах поиска.

Luc 13.07.2020 21:24

@ Люк Да, именно так. Если кто-то думает, что все символы ASCII можно печатать безопасно, он ошибается, но это актуальная тема и заслуживает отдельного вопроса.

wjandrea 13.07.2020 23:43

Другие вопросы по теме