在Python中,如何检查UTF-8字节数组中的字节是否为ASCII a-zA-Z
假设一个UTF-8字节数组,在知道这些字符由单个字节表示的情况下,如何检查任意单个字节是否在字符范围a-zA-Z内?由于这些字符对应的ASCII字母字符整数值在UTF-8中为一个字节,并且多字节字符的任何单个字节都不会与其中一个字符的整数值匹配,因此检查字节的整数值似乎是最快和最安全的 这对我来说很有效,但它是最有效的吗在Python中,如何检查UTF-8字节数组中的字节是否为ASCII a-zA-Z,python,performance,Python,Performance,假设一个UTF-8字节数组,在知道这些字符由单个字节表示的情况下,如何检查任意单个字节是否在字符范围a-zA-Z内?由于这些字符对应的ASCII字母字符整数值在UTF-8中为一个字节,并且多字节字符的任何单个字节都不会与其中一个字符的整数值匹配,因此检查字节的整数值似乎是最快和最安全的 这对我来说很有效,但它是最有效的吗 def isAsciiAlphaByte(c): return ((c>96 and c<123) or (c> 64 and c<91))
def isAsciiAlphaByte(c):
return ((c>96 and c<123) or (c> 64 and c<91))
isAsciiAlphaByte(b"abc"[0])
>>> True
def isAsciiAlphaByte(c):
返回((c>96和c>64和c>True
您可以使用将序列缩减为单个值。在调用str.isalpha
后,我将在字节数组中的每个字节上应用二进制和
:
ba = bytearray('test data')
reduce(lambda x,y: x and y, (chr(b).isalpha() for b in ba))
但真的吗
str(ba).isalpha()
可以很好地工作。正如其他人提到的,非ASCII编码,如UTF-8,是多字节编码。这意味着您会遇到麻烦。下面是如何:
>>> x = bytearray("string","utf8")
>>> y = bytearray([x[0]],"utf8")
>>> print y
s
看起来都不错,但是如果我们不使用所有的英文字母会发生什么呢
>>> x = bytearray(u"touché","utf8")
>>> len(x)
7
哦
>>> y = bytearray([x[-1]])
>>> print y
©
这不好。正如我所评论的,您不需要测试单个字节……但是您可以直接在bytearray类型上使用string方法,包括isalpha()
编辑添加:但是,isalpha()方法似乎没有使用编码来进行每个字符的处理,因此这似乎只适用于ASCII字母。例如:
>>> b2 = bytearray("αβγ", "utf_8")
>>> b2.isalpha()
False
>>> str(b2,"utf_8")
'αβγ'
>>> str(b2,"utf_8").isalpha()
True
>>>
所以,如果你真的需要了解其他字母表的话,这可能不会那么热门。哦,好吧,反正它更快了…:(
PS:我在上面使用了Idle/Python 3.3。在Python 2中,希腊字母需要使用u“”字符串。这个函数看起来像是一个更快的解决方案-根据timeit基准测试,它大约快了50%,根据cProfile基准测试,它大约快了40%速度非常快,节省了编写单独函数的时间。因此两者都可以很好地工作
def isalphabyte(c):
return ((c>96 and c<123) or (c> 64 and c<91))
a=bytearray(b"azAZ 123")
isalphabyte(a[0])
20: True
isalphabyte(a[4])
False
>>> timeit.timeit('for i in range(1000000): chr(b"abc"[0]).isalpha()',number=1)
36: 0.31040439769414263
>>> timeit.timeit('for i in range(1000000): isalphabyte(b"abc"[0])',"from __main__ import isalphabyte",number=1)
37: 0.22895044913212814
>>> cProfile.run('for i in range(1000000): chr(b"abc"[0]).isalpha()')
2000003 function calls in 0.571 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.364 0.364 0.571 0.571 <string>:1(<module>)
1000000 0.156 0.000 0.156 0.000 {built-in method chr}
1 0.000 0.000 0.571 0.571 {built-in method exec}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
1000000 0.051 0.000 0.051 0.000 {method 'isalpha' of 'str' objects}
>>> cProfile.run('for i in range(1000000): isalphabyte(b"abc"[0])')
1000003 function calls in 0.335 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1000000 0.133 0.000 0.133 0.000 <pyshell#74>:1(isalphabyte)
1 0.202 0.202 0.335 0.335 <string>:1(<module>)
1 0.000 0.000 0.335 0.335 {built-in method exec}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
def isalphabyte(c):
return((c>96和c>64以及c>timeit.timeit('对于范围(1000000)中的i):chr(b“abc”[0]).isalpha(),number=1)
36: 0.31040439769414263
>>>timeit.timeit('对于范围(1000000)中的i:isalphabyte(b“abc”[0]),“从主导入isalphabyte”,编号=1)
37: 0.22895044913212814
>>>cProfile.run('对于范围(1000000)中的i:chr(b“abc”[0]).isalpha()'))
2000003次函数调用(0.571秒)
订购人:标准名称
ncalls tottime percall cumtime percall文件名:lineno(函数)
1 0.364 0.364 0.571 0.571 :1()
1000000 0.156 0.000 0.156 0.000{内置方法chr}
1 0.000 0.000 0.571 0.571{内置方法exec}
1 0.000 0.000 0.000 0.000{方法'disable'的''lsprof.Profiler'对象}
1000000 0.051 0.000 0.051 0.000{“str”对象的“isalpha”方法}
>>>cProfile.run('对于范围(1000000)中的i:isalphabyte(b“abc”[0]))
在0.335秒内调用1000003个函数
订购人:标准名称
ncalls tottime percall cumtime percall文件名:lineno(函数)
1000000 0.133 0.000 0.133 0.000:1(isalphabyte)
1 0.202 0.202 0.335 0.335 :1()
1 0.000 0.000 0.335 0.335{内置方法exec}
1 0.000 0.000 0.000 0.000{方法'disable'的''lsprof.Profiler'对象}
您可以对整个bytearray及其片(包括一个字节片)调用.isalpha()
:
上面使用的事实是,尽管utf-8是可变宽度字符编码,但多字节字符中没有单个字节属于字母的ascii范围
它还假定.isalpha()
方法对于bytearray
不依赖于区域设置,例如,b“abаa”。isalpha()
在Python 2中依赖于区域设置
如果要测试单个字节,请执行以下操作:
>>> from curses.ascii import isalpha
>>> b[0]
97
>>> isalpha(b[0]) # it accepts either integer (byte) or a string
True
这没有什么意义,因为UTF-8是一种多字节编码。你不能在UTF-8中测试单个字节。大多数非ASCII代码需要多个字节。听起来他实际上是指ASCII而不是UTF-8。OP应该以这种或那种方式确认这一点。@MarkTolonen如果你理解ASCII字母字符,这是有意义的在UTF-8中是单字节的。现在你已经澄清了你想要的。是的,但我认为这不是特别有效的…我会做一些基准测试。哪一个?我真的怀疑你会打败str(ba)。isalpha()
与任何其他python代码一起使用。我想我只是…只是在bytearray上使用了isalpha!没关系。文档对此不清楚。我收回了答案。@MikeHousky实际上我不知道你可以调用isalpha()
在bytearray
上。不确定为什么这里的答案不正确。注意:我接受了这个答案,但它比我在isAsciiAlphaByte中编写的整数检查慢30-50%。我正在对UTF-8文档进行就地编辑,只想更改某些ASCII值。因为它们始终是单字节,而不是多字节的一部分yte字符我可以这样做。我在你的基准测试中没有看到我的答案中的代码,所以我不明白什么比你问题中的代码慢(bytearray.isalpha应该更快,因为它可以处理很多字节,curses.ascii.isascii可能会慢一些,因为它同时接受整数和字符(bytestrings))如果要替换单个字节,请尝试bytearray.translate()
method我将我的基准放在我发布的答案中。这里列出了最后一个答案。我无法进行翻译,因为不是所有字符都被替换。作为文档递归下降解析的一部分,单个字符被替换,但文档不符合常规语法,因此使用antlr或其他解析器生成器是非常困难的这不是一个真正的选项。这就是为什么我为我的特定目的手工制作了一个。在我看来,这是一个合理的问题,有人可以问。是的。这是我的意思。我没有看到m的代码
>>> a = b"azAZ 123"
>>> b = bytearray(a)
>>> b.isalpha() # not all bytes in the array are ascii letters
False
>>> b[:4].isalpha() # but the first 4 bytes are alphabetic ([a-zA-Z])
True
>>> b[0:1].isalpha() # you need to use the slice notation even for a single byte
True
>>> from curses.ascii import isalpha
>>> b[0]
97
>>> isalpha(b[0]) # it accepts either integer (byte) or a string
True