我有一个包含unicode符号(cyrillic)的字符串:
myString1 = 'Австрия'
myString2 = 'AustriЯ'
我想检查字符串中的所有元素是否都是英文(ASCII)。 现在我使用循环:
for char in myString1:
if ord(s) not in range(65,91):
break
因此,如果我找到第一个非英语元素,我就会打破循环。但是对于给定的示例,您可以看到字符串最后可以包含许多英文符号和unicode。通过这种方式,我将检查整个字符串。此外,如果所有的字符串都是英文的,我仍然会检查每个字符。
有没有更有效的方法来做到这一点?我正在考虑这样的事情:
if any(myString[:]) is not in range(65,91)
答案 0 :(得分:8)
您可以使用set
(O(1)
包含检查)来加快检查速度,尤其是在检查相同范围的多个字符串时,因为初始集创建也需要一次迭代。然后,您可以使用all
来获得比any
更适合的早期迭代模式:
import string
ascii = set(string.ascii_uppercase)
ascii_all = set(string.ascii_uppercase + string.ascii_lowercase)
if all(x in ascii for x in my_string1):
# my_string1 is all ascii
当然,任何all
构造都可以通过DeMorgan's Law转换为any
:
if not any(x not in ascii for x in my_string1):
# my_string1 is all ascii
一种基于纯集的方法,不需要Artyer指出的完整迭代:
if ascii.issuperset(my_string1):
# my_string1 is all ascii
答案 1 :(得分:2)
另一种方式就像@schwobaseggl建议但使用完整集方法:
import string
ascii = string.ascii_uppercase + string.ascii_lowercase
if set(my_string).issubset(ascii):
#myString is ascii
答案 2 :(得分:1)
re
似乎非常快:
import re
# to check whether any outside ranges (->MatchObject) / all in ranges (->None)
nonletter = re.compile('[^a-zA-Z]').search
# to check whether any in ranges (->MatchObject) / all outside ranges (->None)
letter = re.compile('[a-zA-Z]').search
bool(nonletter(myString1))
# True
bool(nonletter(myString2))
# True
bool(nonletter(myString2[:-1]))
# False
OP的两个例子和一个正例的基准(设置是@schwobaseggl setset是@DanielSanchez):
Австрия
re 0.48832818 ± 0.09022105 µs
set 0.58745548 ± 0.01759877 µs
setset 0.81759223 ± 0.03595184 µs
AustriЯ
re 0.51960442 ± 0.01881561 µs
set 1.03043942 ± 0.02453405 µs
setset 0.54060076 ± 0.01505265 µs
tralala
re 0.27832978 ± 0.01462306 µs
set 0.88285526 ± 0.03792728 µs
setset 0.43238688 ± 0.01847240 µs
基准代码:
import types
from timeit import timeit
import re
import string
import numpy as np
def mnsd(trials):
return '{:1.8f} \u00b1 {:10.8f} \u00b5s'.format(np.mean(trials), np.std(trials))
nonletter = re.compile('[^a-zA-Z]').search
letterset = set(string.ascii_letters)
def f_re(stri):
return not nonletter(stri)
def f_set(stri):
return all(x in letterset for x in stri)
def f_setset(stri):
return set(stri).issubset(letterset)
for stri in ('Австрия', 'AustriЯ', 'tralala'):
ref = f_re(stri)
print(stri)
for name, func in list(globals().items()):
if not name.startswith('f_') or not isinstance(func, types.FunctionType):
continue
try:
assert ref == func(stri)
print("{:16s}".format(name[2:]), mnsd([timeit(
'f(stri)', globals={'f':func, 'stri':stri}, number=1000) * 1000 for i in range(1000)]))
except:
print("{:16s} apparently failed".format(name[2:]))
答案 3 :(得分:0)
没有办法避免迭代。
但是,通过not 65 <= ord(s) <= 91
而不是与范围进行比较,您当然可以提高效率。