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






Вы можете использовать библиотеку регулярных выражений, которая принимает стандартное определение 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)
@Sri: Это потому, что вы используете его в незакодированной строке (str в Python 2, bytes в Python 3).
В Python 2 это решение работает только для строки юникод. str в любой кодировке ISO необходимо сначала закодировать в Unicode. Ответ должен заключаться в этом.
@JetGuo: вы должны использовать оба в зависимости от типа ввода: s.decode('ascii') if isinstance(s, bytes) else s.encode('ascii') в Python 3. Ввод OP представляет собой байтовую строку 'é' (синтаксис Python 2, Python 3 не был выпущен в то время), поэтому .decode() является правильным.
@Sri: вы передали строку Unicode вместо строки байтов. Python 2 пытается неявно кодировать с помощью sys.getdefaultencoding() ('ascii'). Если ваш ввод - Unicode; вместо этого явно используйте .encode('ascii', 'strict').
@alexis: неправильно. str на Python 2 - это байтовая строка. Правильно использовать .decode('ascii'), чтобы узнать, все ли байты находятся в диапазоне ascii.
Вопрос @JetGuo OP касался Python 2. Использование mystring.encode('ascii') здесь на самом деле сначала попытается декодировать строку, используя системное значение по умолчанию, чтобы создать строку Unicode, а затем перекодировать эту строку как указанную кодировку, что является плохим способом сделать это. .
def is_ascii(s):
return all(ord(c) < 128 for c in s)
Бессмысленно неэффективно. Гораздо лучше попробовать s.decode ('ascii') и поймать UnicodeDecodeError, как предложил Винсент Маркетти.
Это не неэффективно. all () выполнит короткое замыкание и вернет False, как только обнаружит недопустимый байт.
Неэффективный или нет, более питонический метод - это try / except.
Это неэффективно по сравнению с try / except. Здесь цикл находится в интерпретаторе. В форме try / except цикл находится в реализации кодека C, вызываемом str.decode ('ascii'). И я согласен, форма try / except тоже более питоническая.
-1 Не только цикл по коду Python вместо кода C, но также есть вызов функции Python ord(c) - UGLY - по крайней мере, вместо этого используется c <= "\x7F".
@JohnMachin ord(c) < 128 бесконечно более читабелен и интуитивно понятен, чем c <= "\x7F"
«Неэффективность» зависит от длины строк и вероятности данных ASCII; для коротких строк, не являющихся ASCII, эта функция может быть быстрее, чем установка блока try / except и обработка исключения.
Использование блока try-catch - это не питонизм, а злоупотребление.
Кажется, люди без ума от питонизма, чем от здравомыслия. Этот ответ для меня намного проще, чем попытка, за исключением того, что я хочу использовать его в понимании списка. Я хочу фильтровать большой текстовый корпус, выкидывая все слова, а не ascii. Как бы вы сделали это с помощью try..except?
@BinuJasim Вы по-прежнему можете фильтровать с помощью метода try / catch в понимании списка, если вы заключите его в функцию, которая возвращает True или False в зависимости от того, было ли создано исключение. Тем не менее, ни для одного из этих методов не годится; Помимо эффективности, я думаю, что оба метода хороши, если они существуют как функция с соответствующим именем.
Как насчет этого?
import string
def isAscii(s):
for c in s:
if c not in string.ascii_letters:
return False
return True
Это не сработает, если строка содержит символы ASCII, которые не являются буквами. Для вас примеры кода, которые включают новую строку, пробел, точку, запятую, подчеркивание и круглые скобки.
Ваш вопрос неверен; ошибка, которую вы видите, не является результатом того, как вы построили 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).
Каждый абстрактный символ представляет собой всегда, представленный одной кодовой точкой. Однако кодовые точки могут быть закодированы в несколько байтов, в зависимости от схемы кодирования. т.е. 'é' - это два байта в UTF-8 и UTF-16 и четыре байта в UTF-32, но в каждом случае это по-прежнему одна кодовая точка - U + 00E9.
@Ben Blank: кодовые точки U + 0065 и U + 0301 являются, и они делать представляют собой 'é', которое может быть представлено также как U + 00E9. Гугл «сочетание острого акцента».
J.F. прав, объединив U + 0065 и U + 0301 для образования «é», но это не обратимая функция. Вы получите U + 00E9. Согласно википедия, эти составные кодовые точки полезны для обратной совместимости.
@teehoo - это обратимая функция в том смысле, что вы можете повторно нормализовать кодовую точку, представляющую составной символ, в последовательность кодовых точек, представляющих тот же составной символ. В Python это можно сделать так: unicodedata.normalize ('NFD', u '\ xe9').
Я обновил ответ, чтобы попытаться учесть некоторые из этих отзывов, а также изменения, внесенные в вопрос.
Жало (типа 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 !!!
Не работает. Попробуйте вызвать по следующему номеру: is_ascii(u'i am ascii'). Несмотря на то, что буквы и пробелы определенно являются ASCII, это все равно возвращает False, потому что мы заставили строку быть unicode.
Недавно наткнулся на что-то подобное - на будущее.
import chardet
encoding = chardet.detect(string)
if encoding['encoding'] == 'ascii':
print 'string is in ascii'
который можно использовать с:
string_ascii = string.decode(encoding['encoding']).encode('ascii')
Конечно, для этого нужна библиотека Chardet.
да, хотя chardet доступен по умолчанию в большинстве установок
{'confidence': 0.99, 'encoding': 'EUC-JP'} (which in this case was completely wrong)
Я нашел этот вопрос, пытаясь определить, как использовать / кодировать / декодировать строку, в кодировке которой я не был уверен (и как избежать / преобразовать специальные символы в этой строке).
Моим первым шагом должна была быть проверка типа строки - я не понимал, что могу получить хорошие данные о ее форматировании из типа (ов). Этот ответ был очень полезным и помог мне понять суть моих проблем.
Если вы становитесь грубым и настойчивым
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')
'àéç'
Чтобы предотвратить сбой вашего кода, вы, возможно, захотите использовать 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 продолжил работу.
В 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 байта соответственно, что увеличит их размер.
По @far лучший ответ, но не то, что некоторые символы вроде ... и - могут выглядеть как ascii, поэтому, если вы хотите использовать это для обнаружения английского текста, замените такие символы перед проверкой
Но в Python2 он выдаст UnicodeEncodeError. Надо найти решение как для Py2, так и для Py3
Это просто расточительно. Он кодирует строку в UTF-8, создавая целую другую строку байтов. Истинный способ Python 3 - try: s.encode('ascii'); return Trueexcept UnicodeEncodeError: return False (как и выше, но с кодировкой, поскольку строки являются Unicode в Python 3). Этот ответ также вызывает ошибку в Python 3, когда у вас есть суррогаты (например, isascii('\uD800') вызывает ошибку вместо возврата False)
Это выглядит довольно красиво, но мне интересно, так же ли он эффективен, как all, при обработке длинной строки.
@ChristopheRoussy - эти символы (кодовые точки) будут закодированы в несколько байтов, поэтому то, что вы говорите, не имеет смысла.
Чтобы улучшить решение Александра из 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
Винсент Маркетти придерживается правильной идеи, но 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 верен.
@ J.F.Sebastian OP спрашивает: "Как проверить, находится ли строка в Python в ASCII?" и не указывает байты и строки в Юникоде. Почему вы говорите, что его / ее ввод - это байтовая строка?
посмотрите на дату вопроса: 'é' в то время был байтовой строкой.
@ J.F.Sebastian, хорошо, учитывая, что этот ответ отвечает на этот вопрос, как если бы он был задан сегодня, я думаю, что он по-прежнему актуален и полезен. Все меньше и меньше людей будут приходить сюда в поисках ответов, как если бы они работали на Python в 2008 году.
OP не стал бы задавать этот вопрос сегодня: ord('é') == 1 на Python 3 (в целом может быть> 1, но это не связано с тем, что строка находится в диапазоне ascii или нет). В любом случае, если не указано, является ли входная строка Unicode; оба могут использоваться: s.decode('ascii') if isinstance(s, bytes) else s.encode('ascii')
Я нашел этот вопрос, когда искал решение для python3, и быстрое прочтение вопроса не заставило меня заподозрить, что это специфика python 2. Но этот ответ был действительно полезным - голосование за!
Мне этот ответ нравится намного больше, поскольку я использую Python3, в котором все строки по определению являются строками Unicode, в результате чего будет вызывать метод .encode(). Этот ответ кажется более питоническим, чем другой ответ о сравнении длины символа до и после кодирования.
Это решение, совместимое с py2 и py3, которое я искал!
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
Я полагаю, что регулярное выражение хорошо оптимизировано для этого.
Больше никаких утомительных / неэффективных проверок 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 Полезно знать, но ASCII включает управляющие символы. Избегать их - другая тема.
@wjandrea Да, очевидно, но то, что 0x03 умещается в 7 битах, не означает, что это то, что большинство людей захотят проверять, когда найдут эту страницу в своих результатах поиска.
@ Люк Да, именно так. Если кто-то думает, что все символы ASCII можно печатать безопасно, он ошибается, но это актуальная тема и заслуживает отдельного вопроса.
Кодировка строк в Python 2 и Python 3 немного отличается, поэтому было бы неплохо знать, на какую версию вы нацеливаетесь.