在动漫中,Ente Isla中的语言称为Entean,基本上是英语字母表中大多数辅音转换的地方。元音和辅音“ L”,“ N”,“ Q”保持其原始位置。 ABCDEFGHIJKLMNOPQRSTUVWXYZ更改为AZYXEWVTISRLPNOMQKJHUGFDCB。例如,“人”为“ tupan”,“世界”为“ foklx”。
代码如下:
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/英文对整个国家
#1 楼
最惯用的Python解决方案是使用str.translate()
函数,该函数恰好解决了这个问题。我看不出有什么理由将输入拆分为单词,然后将结果重新组合在一起。只需一次翻译整个字符串(空间映射到其自身)。
#2 楼
使用字典我们基本上只是将一个字母映射到下一个字母。最自然的方法是实际使用地图:
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:")
^^^^^^^
#3 楼
Barry和200_success提出了一些算法建议,与您的原始版本和我自己的两个修改版本相比,我可以验证以后的速度。但是在处理这些版本之前,请先检查您的代码:避免使用顶级代码-在脚本中,您从一些常量开始,然后在顶级请求文本,然后定义一个函数
get_letter
,然后处理您要的文本。这不干净。如果引入翻译整个文本的功能和主要功能,则可以将此代码模块化。 然后,您就可以从另一个脚本(即下载动漫的脚本)导入模块,并且可以从模块中调用
to_entean()
。要仍然允许将此脚本作为脚本运行,请在文件末尾使用if __name__ == '__main__': main()
。请参见下面的代码示例重复使用时,函数的存储结果–对于每个字母,您执行
alphabet.find()
三次,两次执行过多。 错误1:将
eng_letter
和letter
混合在get_letter()
中–这是失败的,您可能在将代码复制粘贴到Code Review中时引入了这些错误...错误2:标点符号错误翻译–使用find时,找不到字母时返回-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
之前,有时在逻辑代码块之前添加空白行。还要注意,函数前面应该有两个空行拆分,添加和剥离字符串会有点昂贵–大多数时候,您的代码都是这样做的。了解您的选择,然后选择最适合您的一种。重构代码时,我保留一个版本进行拆分,并且一个版本像Barry一样加入。请参阅这两者的时差。
代码重构
根据我的评论进行重构时,我得到以下代码:
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()
简化为单个返回字母同时使用大写和小写字母。 使用连接的
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中进行了测试,但我认为即使对于Python 3而言,相同的差异也将保持。请注意,对代码进行性能测试有点徒劳,但是对于查看代码更改也如何影响性能可能很有用。 我运行的测试是:
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
中)更改为连接(在main
中),时间节省了近10%。使用dict's(在main_v2
中),main_barry
和upper()
比原始代码快,但比isupper()
慢。在我和Barry的find()
版本中,我都使用了不带join
的版本,如果使用map()
,则时间缩短了4-6 µs。 关于测试与各种解决方案的初始化成本相关的性能的注意事项,因为Barry和200_success的版本都具有较小的初始化成本(上述时间中未包括)。但这速度为60-70 µs,因此,如果执行翻译负载,则可以花费更多的时间进行初始化。
通过所有这些操作可中学到的主要经验教训是两方面的:
使用诸如
map()
之类的专用资源通常可以大幅度减少执行时间清理代码并避免不必要的操作,也可能对执行时间产生重大影响(在这种情况下,速度提高了近50%)。更不用说它更易于维护并返回到以后的阶段
评论
\ $ \ begingroup \ $
str.translate()的性能在两个版本之间没有太大变化的假设实际上是无效的:Python 3.4和3.5之间存在巨大差异。
\ $ \ endgroup \ $
– 200_success
15年12月16日在9:32
\ $ \ begingroup \ $
@ 200_success它在3.5中运行得更快,因此str.translate甚至更快。您是否知道翻译的速度是否会慢于其他选择,而这会破坏我的建议?
\ $ \ endgroup \ $
– Holroy
15年12月16日在11:36
#4 楼
这是您的完整程序,使用200_success建议使用str.translate
重新实现:from string import ascii_letters as alphabet
switched = 'azyxewvtisrlpnomqkjhugfdcb'
switched += switched.upper()
entean_translation = str.maketrans(alphabet, switched)
user_text = input("Enter Englsih text:")
print(user_text)
print(user_text.translate(entean_translation))
评论
问题标题应反映代码的功能,因此我编辑了您的标题以反映代码。当您在get_letter()中混合字母和eng_letter时,您的代码已损坏。
我已根据接受的答案codereview.stackexchange.com/questions/112016/…中的建议创建了脚本的更新版本。
我注意到您已将接受的答案切换为仅代码的答案。您可能应该考虑社区对此做法的看法。
@ 200_success我以为您可以在看到多个答案上的勾号时选择多个答案。我不知道它会切换答案。感谢您指出这一点。