240

我想检查一个字符串是否为 ASCII 格式。

我知道ord(),但是当我尝试时ord('é'),我知道了TypeError: ord() expected a character, but string of length 2 found。我知道这是由我构建 Python 的方式引起的(如ord()'s documentation中所述)。

有没有其他方法可以检查?

4

16 回答 16

276

我认为你没有问正确的问题——

python 中的字符串没有对应于“ascii”、utf-8 或任何其他编码的属性。您的字符串的来源(无论您是从文件中读取它,还是从键盘输入等)可能已经在 ascii 中编码了一个 unicode 字符串来生成您的字符串,但这就是您需要寻找答案的地方。

也许你可以问的问题是:“这个字符串是用 ascii 编码一个 unicode 字符串的结果吗?” - 你可以通过尝试回答:

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"
于 2008-10-13T00:30:32.367 回答
220
def is_ascii(s):
    return all(ord(c) < 128 for c in s)
于 2008-10-13T00:30:43.257 回答
174

在 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
于 2013-08-23T13:14:49.313 回答
129

Python 3.7 中的新功能 ( bpo32677 )

不再对字符串进行烦人/低效的 ascii 检查,新的内置str//方法 -将检查字符串是否为 ascii。bytesbytearray.isascii()

print("is this ascii?".isascii())
# True
于 2018-07-02T18:32:22.840 回答
28

Vincent Marchetti 有正确的想法,但str.decode在 Python 3 中已被弃用。在 Python 3 中,您可以使用以下命令进行相同的测试str.encode

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

请注意,您要捕获的异常也已从 更改UnicodeDecodeErrorUnicodeEncodeError

于 2015-09-02T15:45:04.567 回答
18

你的问题不正确;您看到的错误不是您如何构建 python 的结果,而是字节字符串和 unicode 字符串之间的混淆。

字节字符串(例如,python 语法中的“foo”或“bar”)是八位字节序列;数字从 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') == 2len(u'\u00e9') == 1。如果这对您很重要,您可以使用unicodedata.normalize.

Unicode 词汇表可以成为理解其中一些问题的有用指南,它指出每个特定术语如何指代文本表示的不同部分,这比许多程序员意识到的要复杂得多。

于 2008-10-14T07:36:59.590 回答
18

最近遇到这样的事情 - 以供将来参考

import chardet

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

您可以使用:

string_ascii = string.decode(encoding['encoding']).encode('ascii')
于 2011-08-08T20:47:22.390 回答
9

这样做怎么样?

import string

def isAscii(s):
    for c in s:
        if c not in string.ascii_letters:
            return False
    return True
于 2008-10-13T16:38:25.517 回答
9

我在尝试确定如何使用/编码/解码我不确定其编码的字符串(以及如何转义/转换该字符串中的特殊字符)时发现了这个问题。

我的第一步应该是检查字符串的类型——我没有意识到我可以从类型中获得关于其格式的良好数据。 这个答案非常有帮助,并找到了我问题的真正根源。

如果你变得粗鲁和执着

UnicodeDecodeError:“ascii”编解码器无法解码位置 263 中的字节 0xc3:序数不在范围内(128)

特别是当你编码时,确保你没有尝试 unicode() 一个已经是 unicode 的字符串——由于某些可怕的原因,你会得到 ascii 编解码器错误。(另请参阅Python Kitchen recipePython 文档教程,以更好地了解这有多可怕。)

最终我确定我想做的是:

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

对调试也有帮助的是将我的文件中的默认编码设置为 utf-8(将其放在 python 文件的开头):

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

这允许您测试特殊字符 ('àéç'),而不必使用它们的 unicode 转义 (u'\xe0\xe9\xe7')。

>>> specials='àéç'
>>> specials.decode('latin-1').encode('ascii','xmlcharrefreplace')
'&#224;&#233;&#231;'
于 2012-08-21T23:24:35.620 回答
4

要从 Python 2.6(和 Python 3.x)改进 Alexander 的解决方案,您可以使用辅助模块 curses.ascii 并使用 curses.ascii.isascii() 函数或其他各种:https ://docs.python.org/2.6/图书馆/curses.ascii.html

from curses import ascii

def isascii(s):
    return all(ascii.isascii(c) for c in s)
于 2015-05-22T08:48:46.607 回答
2

您可以使用接受 Posix 标准 [[:ASCII:]] 定义的正则表达式库。

于 2008-10-13T00:18:25.560 回答
2

Python 中的字符串 ( str-type) 是一系列字节。无法仅通过查看字符串来判断这一系列字节是表示 ascii 字符串、8 位字符集中的字符串(如 ISO-8859-1)还是用 UTF-8 或 UTF-16 编码的字符串或其他字符串.

但是,如果您知道使用的编码,那么您可以decode将 str 转换为 unicode 字符串,然后使用正则表达式(或循环)来检查它是否包含您关注的范围之外的字符。

于 2008-10-14T07:58:08.173 回答
1

就像@RogerDahl 的回答find_all一样,但通过否定字符类并使用 search 而不是or来短路更有效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

我想正则表达式对此进行了很好的优化。

于 2016-10-28T16:30:33.790 回答
0
import re

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

+要将空字符串包含为 ASCII,请将*.

于 2015-09-30T14:51:52.030 回答
-2

为了防止您的代码崩溃,您可能需要使用 atry-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
于 2013-07-07T21:16:00.113 回答
-5

我使用以下内容来确定字符串是 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
于 2010-07-21T06:34:56.927 回答