我写了一个python脚本,从一个叫做“魔鬼是部分定时器”的动画把英语转换成Entean语言。我在编码方面很马虎,我知道这个脚本可以做得更好。
在动画中,English的语言叫做Entean,它基本上是英语字母表中的大部分辅音。元音和辅音'L','N','Q‘保持他们原来的位置。ABCDEFGHIJKLMNOPQRSTUVWXYZ改为AZYXEWVTISRLPNOMQKJHUGFDCB。例如,“人”是“土豆泥”,而“世界”则是“狐狸”。
以下是代码:
alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".lower()
switched = "AZYXEWVTISRLPNOMQKJHUGFDCB".lower()
usr_txt = input("Enter Englsih text:")
print(usr_txt)
def get_letter(eng_letter):
if alphabet.find(letter):
if eng_letter.isupper():
alpha_place = alphabet.find(letter.lower())
return(switched[alpha_place].upper())
else:
alpha_place = alphabet.find(letter.lower())
return(switched[alpha_place])
else:
return(eng_letter)
ent_word = ""
ent_output = ""
for word in usr_txt.split(" "):
ent_word = ""
for letter in word:
ent_letter = get_letter(letter)
ent_word += ent_letter
ent_output += " " + ent_word
print(ent_output.strip())如果您感兴趣,可以在https://github.com/Logmytech/English-to-Entean找到更新的代码
发布于 2015-11-25 17:40:25
最惯用的Python解决方案是使用str.translate()函数,它正好解决了这个问题。
我看不出有什么理由把输入分成几个字,然后把结果重新组合在一起。只需一次转换整个字符串(其中空间映射到自身)。
发布于 2015-11-25 16:35:32
我们基本上只是从一个字母映射到另一个字母。最自然的方法是实际使用地图:
to_entean = {...}建立字典的最简单方法是使用zip():
to_entean = {eng: ent
for eng, ent in zip(string.ascii_uppercase, 'AZYXEWVTISRLPNOMQKJHUGFDCB')
}现在,to_entean['A'] == 'A'和to_entean['B'] == 'Z'等等。这简化了您的get_letter函数,使其:
def get_letter(letter):
ent = to_entean.get(letter.upper(), letter)
if not letter.isupper():
ent = ent.lower()
return ent字符串连接速度很慢。而且它读起来很可怕。我们要做的是对get_letter中的每一个字母调用word,然后将它们连接到一起。这就是join()的目的:
ent_word = ''.join(get_letter(letter) for letter in word)因为get_letter()已经处理了空格,所以我们不必分词。只是改变了整件事
print(''.join(get_letter(letter) for letter in usr_txt))如果您愿意,也可以拼写如下:
print(''.join(map(get_letter, usr_txt)))你在这里有个错误:
usr_txt = input("Enter Englsih text:")
^^^^^^^发布于 2015-11-25 20:39:10
Barry和200_success提出了一些算法建议,我验证了与您的原始版本和我自己的两个修改版本相比以后的速度。但是在处理这些版本之前,让我们回顾一下您的代码:
get_letter。这里不干净。如果您引入一个函数来翻译整个文本,并且引入一个主函数,则可以将此代码模块化。然后,您将能够从另一个脚本(即下载动画的脚本)导入您的模块,并且您可以从模块调用您的to_entean()。要仍然允许将其作为脚本运行,请在文件末尾使用if __name__ == '__main__': main()。参见下面的代码示例alphabet.find(),即它太多了两次。做一次,然后就结束了。eng_letter和letter混合在get_letter() - This中是一个失败,您可能在将代码复制粘贴到代码审查时引入它.他们应该还是一样的-1,这在Python中是一个合法的索引,因此它很高兴地返回该位置的字符:b。ent_word、eng_letter或usr_txt之类的东西应该被拼出来,比如entean_word、english_letter或user_text。从长远来看,这样做对每个人来说都更容易。UPPER_SNAKE_CASE,以清楚地将它们识别为常量。lower()和upper()操作。特别是设置常量时,这是浪费的。在get_letter()中,这是更容易理解的,但是如果您用小写和大写字母将常量加倍,则不需要调用任何位置。get_letter()非常精简,很难读懂,而且所有的return语句混合在一起,很难看出到底发生了什么。我的规则是在if、elif、else、for和while之前添加空行,有时在逻辑代码块前面添加空行。还请注意,函数的前面应该有两个空行。根据我的评论进行重构时,我将得到以下代码:
FULL_ENGLISH_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
FULL_ENTEAN_ALPHABET = "AZYXEWVTISRLPNOMQKJHUGFDCBazyxewvtisrlpnomqkjhugfdcb"
def get_letter(letter):
"""Return english letter translated to entean."""
alpha_place = FULL_ENGLISH_ALPHABET.find(letter)
return FULL_ENTEAN_ALPHABET[alpha_place] if alpha_place >= 0 else letter
def to_entean(text):
"""Return text translated from english to entean."""
entean_output = ""
for word in text.split(" "):
entean_word = ""
for letter in word:
entean_letter = get_letter(letter)
entean_word += entean_letter
entean_output += " " + entean_word
return entean_output.strip()
def main(text=None, with_output=False):
if with_output:
print("\nmain")
if text is None:
text = input("Enter English text: ")
if with_output:
print(text)
entean_text = to_entean(text)
if with_output:
print(entean_text)main()的默认参数用于增强下面的测试,因此可以编写得更简单。如果在编写时不考虑其他版本,我很可能也会从常量中去掉FULL_。
请注意,当我找到一个字母时,我还将整个get_letter()简化为一个返回,并将字母表扩展到大写字符和小写字符。
使用join的to_entean()的替代版本如下:
def to_entean_join(text):
"""Return text translated from english to entean."""
return ''.join(get_letter(letter) for letter in text)使用上述main()方法的变体,我测试了您的原始版本、我的版本和200_success版本。我在IPython 2中进行了测试,但我假设即使是Python3也会保持相同的差异。请注意,测试这段代码的性能有点徒劳无益,但是它对于查看代码中的变化如何影响性能也是有用的。
我做的测试是:
In [1]: for test_main in (main_org, main_barry, main, main_v2, main_200_success):
...: print('{:<16}: '.format(test_main.__name__), end='')
...: %timeit test_main("Hello world! Welcome humans to the Entean world. This text is written in Entean. Cool?")
...:它提供了以下输出:
main_org : 10000 loops, best of 3: 93.2 µs per loop
main_barry : 10000 loops, best of 3: 70.7 µs per loop
main : 10000 loops, best of 3: 57.6 µs per loop
main_v2 : 10000 loops, best of 3: 52.7 µs per loop
main_200_success: The slowest run took 6.24 times longer than the fastest. This could mean that an intermediate result is being cached
1000000 loops, best of 3: 649 ns per loop可以看出,从性能上看,最明显的赢家是200_success的版本,因为这是一个使用专门翻译方法的专门版本。
另一个有趣的事实是,从分裂、添加和剥离(在main中)到连接(在main_v2中)几乎减少了10%的时间。使用dict(在main_barry中)、upper()和isupper()比原始代码快,但比find()慢。在我和巴里的join版本中,我都使用了一个没有map()的版本,如果使用map()的话,时间会改善4-6秒S。
关于测试与各种解决方案初始化成本相关的性能的说明,因为Barry和200_success的版本都有较小的初始化成本(不包括在上面的时间)。但这是在60-70岁S的速度,因此,如果做大量的翻译,它可以合理地使用更多的时间初始化。
从这一切中吸取的主要教训是两方面的:
str_translate() )通常可以大大缩短执行时间。https://codereview.stackexchange.com/questions/111814
复制相似问题