Làm cách nào để kiểm tra xem một chuỗi trong Python có trong ASCII không?


211

Tôi muốn kiểm tra xem một chuỗi có trong ASCII hay không.

Tôi nhận thức được ord(), tuy nhiên khi tôi cố gắng ord('é'), tôi có TypeError: ord() expected a character, but string of length 2 found. Tôi hiểu nó được gây ra bởi cách tôi xây dựng Python (như được giải thích trong ord()tài liệu của ).

Có cách nào khác để kiểm tra?


Mã hóa chuỗi khác nhau một chút giữa Python 2 và Python 3, vì vậy sẽ rất tốt nếu biết bạn đang nhắm mục tiêu phiên bản nào.
florisla

Câu trả lời:


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

95
Vô hiệu quả. Tốt hơn nhiều để thử s.decode ('ascii') và bắt UnicodeDecodeError, như đề xuất của Vincent Marchetti.
ddaa

20
Nó không hiệu quả. all () sẽ đoản mạch và trả về Sai ngay khi gặp byte không hợp lệ.
John Millikin

10
Không hiệu quả hay không, phương pháp pythonic nhiều hơn là thử / ngoại trừ.
Jeremy Cantrell

43
Đó là không hiệu quả so với thử / ngoại trừ. Ở đây vòng lặp là trong trình thông dịch. Với dạng thử / ngoại trừ, vòng lặp nằm trong triển khai codec C được gọi bởi str.decode ('ascii'). Và tôi đồng ý, hình thức thử / ngoại trừ cũng nhiều pythonic hơn.
ddaa

25
@JohnMachin ord(c) < 128vô cùng dễ đọc và trực quan hơnc <= "\x7F"
Slater Victoroff

252

Tôi nghĩ rằng bạn không hỏi đúng câu hỏi--

Một chuỗi trong python không có thuộc tính tương ứng với 'ascii', utf-8 hoặc bất kỳ mã hóa nào khác. Nguồn của chuỗi của bạn (cho dù bạn đọc nó từ tệp, nhập từ bàn phím, v.v.) có thể đã mã hóa chuỗi unicode trong ascii để tạo chuỗi của bạn, nhưng đó là nơi bạn cần phải trả lời.

Có lẽ câu hỏi bạn có thể hỏi là: "Chuỗi này có phải là kết quả của việc mã hóa chuỗi unicode trong ascii không?" - Điều này bạn có thể trả lời bằng cách thử:

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"

28
sử dụng mã hóa là tốt hơn, bởi vì chuỗi không có phương thức giải mã trong python 3, hãy xem sự khác biệt giữa mã hóa / giải mã là gì? (trăn 2.x)
Jet Guo

@Sri: Đó là bởi vì bạn đang sử dụng nó trên một chuỗi chưa được mã hóa ( strtrong Python 2, bytestrong Python 3).
dotancohen

Trong Python 2, giải pháp này chỉ hoạt động đối với một chuỗi unicode . Trước tiên, strbất kỳ mã hóa ISO nào cũng cần được mã hóa thành Unicode. Câu trả lời nên đi vào đây.
alexis

@JetGuo: bạn nên sử dụng cả hai tùy thuộc vào loại đầu vào: s.decode('ascii') if isinstance(s, bytes) else s.encode('ascii')trong Python 3. Đầu vào của OP là một phép phụ 'é'(cú pháp Python 2, Python 3 chưa được phát hành vào thời điểm đó) và do đó .decode()là chính xác.
jfs

2
@alexis: sai rồi. strtrên Python 2 là một bytestring. Nó là chính xác để sử dụng .decode('ascii')để tìm hiểu xem tất cả các byte có trong phạm vi ascii.
jfs

153

Python 3 cách:

isascii = lambda s: len(s) == len(s.encode())

Để kiểm tra, vượt qua chuỗi kiểm tra:

str1 = "♥O◘♦♥O◘♦"
str2 = "Python"

print(isascii(str1)) -> will return False
print(isascii(str2)) -> will return True

7
Đây là một mẹo nhỏ hay để phát hiện các ký tự không phải mã ascii trong chuỗi Unicode, trong python3 có khá nhiều chuỗi. Vì các ký tự ascii có thể được mã hóa chỉ bằng 1 byte, do đó, bất kỳ độ dài ký tự ascii nào cũng sẽ đúng với kích thước của nó sau khi được mã hóa thành byte; trong khi các ký tự không phải mã ascii khác sẽ được mã hóa thành 2 byte hoặc 3 byte tương ứng sẽ làm tăng kích thước của chúng.
Devy

Bởi @far câu trả lời tốt nhất, nhưng không phải là một số ký tự như Lọ và - có thể trông giống như ascii, vì vậy trong trường hợp bạn muốn sử dụng điều này để phát hiện văn bản tiếng Anh, hãy thay thế các ký tự như vậy trước khi kiểm tra
Barshe Roussy

1
Nhưng trong Python2, nó sẽ ném UnicodeEncodeError. Phải tìm một giải pháp cho cả Py2 và Py3
alvas

2
Đối với những người không quen sử dụng lambda (như tôi khi tôi lần đầu tiên bắt gặp câu trả lời này) isasciigiờ đây là một hàm mà bạn truyền một chuỗi: isascii('somestring')== Trueisascii('àéç')==False
rabidang3ls

8
Điều này chỉ đơn giản là lãng phí. Nó mã hóa một chuỗi trong UTF-8, tạo ra một sự kiểm soát hoàn toàn khác. True Python 3 cách là try: s.encode('ascii'); return True except UnicodeEncodeError: return False(Giống như ở trên, nhưng mã hóa, vì các chuỗi là Unicode trong Python 3). Câu trả lời này cũng gây ra lỗi trong Python 3 khi bạn có người thay thế (ví dụ: isascii('\uD800')phát sinh lỗi thay vì quay lại False)
Artyer

71

Mới trong Python 3.7 ( bpo32677 )

Không mệt mỏi hơn / kiểm tra ascii không hiệu quả trên dây, mới được xây dựng-in str/ bytes/ bytearrayphương pháp - .isascii()sẽ kiểm tra xem chuỗi là ascii.

print("is this ascii?".isascii())
# True

Điều này xứng đáng được đứng đầu!
Salek

"\x03".isascii()cũng đúng Tài liệu nói rằng điều này chỉ kiểm tra rằng tất cả các ký tự nằm dưới mã điểm 128 (0-127). Nếu bạn cũng muốn tránh các ký tự điều khiển, bạn sẽ cần : text.isascii() and text.isprintable(). Chỉ sử dụng isprintablebản thân nó là không đủ, vì nó sẽ coi một ký tự như ¿có thể in được (chính xác), nhưng nó không nằm trong phần có thể in ascii, vì vậy bạn cần kiểm tra cả hai nếu bạn muốn cả hai. Một gotcha khác: không gian được coi là có thể in, các tab và dòng mới thì không.
Lục

19

Chạy vào một cái gì đó như thế này gần đây - để tham khảo trong tương lai

import chardet

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

mà bạn có thể sử dụng với:

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

7
Tất nhiên, điều này đòi hỏi thư viện chardet .
StackExchange làm buồn nhảy dancek

1
có, mặc dù chardet có sẵn theo mặc định trong hầu hết các cài đặt
Alvin

7
chardet chỉ đoán mã hóa với một xác suất nhất định như thế này: {'confidence': 0.99, 'encoding': 'EUC-JP'}(trong trường hợp này là hoàn toàn sai)
Suzana

19

Vincent Marchetti có ý tưởng đúng, nhưng str.decodeđã bị phản đối trong Python 3. Trong Python 3, bạn có thể thực hiện cùng một bài kiểm tra với str.encode:

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

Lưu ý ngoại lệ bạn muốn bắt cũng đã thay đổi từ UnicodeDecodeErrorthành UnicodeEncodeError.


Đầu vào của OP là một bytestring ( bytesgõ trong Python 3 không có .encode()phương thức). .decode()trong câu trả lời của @Vincent Marchetti là chính xác .
jfs

@JFSebastian OP hỏi "Làm thế nào để kiểm tra xem một chuỗi trong Python có trong ASCII không?" và không chỉ định byte so với chuỗi unicode. Tại sao bạn nói đầu vào của anh ấy / cô ấy là một bytestring?
drs

1
nhìn vào ngày của câu hỏi: 'é'là một sự tạm biệt vào thời điểm đó.
jfs

1
@JFSebastian, ok, xem xét câu trả lời này trả lời câu hỏi này như thể nó được hỏi ngày hôm nay, tôi nghĩ nó vẫn còn hiệu lực và hữu ích. Càng ngày càng ít người sẽ đến đây để tìm kiếm câu trả lời như thể họ đang chạy Python vào năm 2008
drs

2
Tôi đã tìm thấy câu hỏi này khi tôi đang tìm kiếm một giải pháp cho python3 và nhanh chóng đọc câu hỏi không khiến tôi nghi ngờ rằng đây là python 2 specfic. Nhưng câu trả lời này thực sự hữu ích - nâng cao!
josch

17

Câu hỏi của bạn không chính xác; lỗi bạn thấy không phải là kết quả của cách bạn tạo python, mà là sự nhầm lẫn giữa chuỗi byte và chuỗi unicode.

Chuỗi byte (ví dụ "foo" hoặc 'bar', theo cú pháp python) là chuỗi các octet; các số từ 0-255. Chuỗi Unicode (ví dụ: u "foo" hoặc u'bar ') là chuỗi các điểm mã unicode; số từ 0-1112064. Nhưng bạn có vẻ hứng thú với ký tự é, trong đó (trong thiết bị đầu cuối của bạn) là một chuỗi nhiều byte đại diện cho một ký tự.

Thay vì ord(u'é'), hãy thử điều này:

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

Điều đó cho bạn biết chuỗi điểm nào "é" đại diện. Nó có thể cung cấp cho bạn [233] hoặc có thể cung cấp cho bạn [101, 770].

Thay vì chr()đảo ngược điều này, có unichr():

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

Ký tự này thực sự có thể được biểu diễn bằng một hoặc nhiều "điểm mã" đơn, mà chính chúng đại diện cho biểu đồ hoặc ký tự. Đó là "e với dấu trọng âm (nghĩa là mã điểm 233)" hoặc "e" (mã điểm 101), theo sau là "dấu trọng âm trên ký tự trước" (điểm mã 770). Vì vậy, chính xác ký tự này có thể được trình bày dưới dạng cấu trúc dữ liệu Python u'e\u0301'hoặc u'\u00e9'.

Hầu hết thời gian bạn không cần phải quan tâm đến vấn đề này, nhưng nó có thể trở thành vấn đề nếu bạn lặp qua chuỗi unicode, vì phép lặp hoạt động theo điểm mã chứ không phải bằng ký tự có thể phân tách. Nói cách khác, len(u'e\u0301') == 2len(u'\u00e9') == 1. Nếu điều này quan trọng với bạn, bạn có thể chuyển đổi giữa các hình thức sáng tác và phân tách bằng cách sử dụngunicodedata.normalize .

Thuật ngữ Unicode có thể là một hướng dẫn hữu ích để hiểu một số vấn đề này, bằng cách chỉ ra cách mỗi thuật ngữ cụ thể đề cập đến một phần khác nhau của cách trình bày văn bản, phức tạp hơn nhiều so với nhiều lập trình viên nhận ra.


3
'É' không nhất thiết phải đại diện cho một điểm mã duy nhất. Nó có thể là hai điểm mã (U + 0065 + U + 0301).
JFS

2
Mỗi ký tự trừu tượng luôn được đại diện bởi một điểm mã duy nhất. Tuy nhiên, các điểm mã có thể được mã hóa thành nhiều byte, tùy thuộc vào sơ đồ mã hóa. tức là, 'é' là hai byte trong UTF-8 và UTF-16 và bốn byte trong UTF-32, nhưng trong mỗi trường hợp vẫn là một điểm mã duy nhất - U + 00E9.
Ben Trống

5
@Ben Blank: U + 0065 và U + 0301 điểm mã và họ làm đại diện cho 'é' mà có thể cũng được đại diện bởi U + 00E9. Google "kết hợp giọng cấp tính".
JFS

JF đã đúng khi kết hợp U + 0065 và U + 0301 để tạo thành 'é' nhưng đây không phải là một funcino có thể đảo ngược. Bạn sẽ nhận được U + 00E9. Theo wikipedia , các điểm mã tổng hợp này rất hữu ích cho khả năng tương thích ngược
Martin Konecny

1
@teehoo - Đây là một chức năng có thể đảo ngược theo nghĩa là bạn có thể bình thường hóa điểm mã đại diện cho ký tự được tạo thành một chuỗi các điểm mã đại diện cho cùng một ký tự. Trong Python bạn có thể làm như vậy: unicodingata.n normalize ('NFD', u '\ xe9').
Glyph

10

Làm thế nào về việc này?

import string

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

5
Điều này không thành công nếu chuỗi của bạn chứa các ký tự ASCII không phải là chữ cái. Đối với bạn ví dụ mã, bao gồm dòng mới, dấu cách, dấu chấm, dấu phẩy, dấu gạch dưới và dấu ngoặc đơn.
florisla

9

Tôi đã tìm thấy câu hỏi này trong khi thử xác định cách sử dụng / mã hóa / giải mã một chuỗi có mã hóa mà tôi không chắc chắn (và cách thoát / chuyển đổi các ký tự đặc biệt trong chuỗi đó).

Bước đầu tiên của tôi là kiểm tra loại chuỗi - Tôi không nhận ra ở đó tôi có thể nhận được dữ liệu tốt về định dạng của chuỗi từ loại. Câu trả lời này rất hữu ích và đi đến gốc rễ thực sự của các vấn đề của tôi.

Nếu bạn đang trở nên thô lỗ và cố chấp

UnicodeDecodeError: 'ascii' codec không thể giải mã byte 0xc3 ở vị trí 263: thứ tự không nằm trong phạm vi (128)

đặc biệt là khi bạn ENCODING, hãy đảm bảo rằng bạn không cố gắng unicode () một chuỗi đã là unicode - vì một số lý do khủng khiếp, bạn gặp phải lỗi codec ascii. (Xem thêm công thức Python Kitchentài liệu Python hướng dẫn về để hiểu rõ hơn về mức độ khủng khiếp của nó.)

Cuối cùng tôi xác định rằng những gì tôi muốn làm là thế này:

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

Cũng hữu ích trong việc gỡ lỗi là đặt mã hóa mặc định trong tệp của tôi thành utf-8 (đặt phần này vào đầu tệp python của bạn):

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

Điều đó cho phép bạn kiểm tra các ký tự đặc biệt ('àéç') mà không phải sử dụng các lối thoát unicode của chúng (u '\ xe0 \ xe9 \ xe7').

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

4

Để cải thiện giải pháp của Alexandre từ Python 2.6 (và trong Python 3.x), bạn có thể sử dụng mô đun trình trợ giúp curses.ascii và sử dụng hàm curses.ascii.isascii () hoặc nhiều cách khác: https://docs.python.org/2.6/ thư viện / curses.ascii.html

from curses import ascii

def isascii(s):
    return all(ascii.isascii(c) for c in s)


2

Bạn có thể sử dụng thư viện biểu thức chính quy chấp nhận định nghĩa Posix [[: ASCII:]].


2

Một sting ( str-type) trong Python là một chuỗi các byte. Không có cách nào để chỉ nhìn vào chuỗi xem chuỗi byte này đại diện cho chuỗi ascii, chuỗi trong bộ ký tự 8 bit như ISO-8859-1 hay chuỗi được mã hóa bằng UTF-8 hoặc UTF-16 hay bất cứ điều gì .

Tuy nhiên, nếu bạn biết mã hóa được sử dụng, thì bạn có thể decodestr thành chuỗi unicode và sau đó sử dụng biểu thức chính quy (hoặc vòng lặp) để kiểm tra xem nó có chứa các ký tự ngoài phạm vi bạn quan tâm không.


1

Giống như câu trả lời của @ RogerDahl nhưng hiệu quả hơn là đoản mạch bằng cách phủ định lớp nhân vật và sử dụng tìm kiếm thay vì find_allhoặc 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

Tôi tưởng tượng một biểu thức chính quy được tối ưu hóa tốt cho việc này.


0
import re

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

Để bao gồm một chuỗi rỗng như ASCII, thay đổi +thành *.


-1

Để ngăn mã của bạn gặp sự cố, bạn có thể muốn sử dụng try-exceptđể bắtTypeErrors

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

Ví dụ

def is_ascii(s):
    try:
        return all(ord(c) < 128 for c in s)
    except TypeError:
        return False

Đây trywrapper là hoàn toàn vô nghĩa. Nếu "¶"là một chuỗi Unicode, thì nó ord("¶")sẽ hoạt động và nếu không phải là (Python 2), for c in ssẽ phân tách nó thành byte nên ordsẽ tiếp tục hoạt động.
Ry-

-5

Tôi sử dụng như sau để xác định xem chuỗi là ascii hay unicode:

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

Sau đó, chỉ cần sử dụng một khối có điều kiện để xác định chức năng:

def is_ascii(input):
    if input.__class__.__name__ == "str":
        return True
    return False

4
-1 AARRGGHH điều này đang coi tất cả các ký tự có ord (c) trong phạm vi (128, 256) là ASCII !!!
John Machin

Không hoạt động. Hãy thử gọi như sau : is_ascii(u'i am ascii'). Mặc dù các chữ cái và dấu cách chắc chắn là ASCII, nhưng điều này vẫn trả về Falsevì chúng ta đã buộc chuỗi phải unicode.
jpmc26
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.