我编写了一个python脚本,将动漫中的英语转换为Entean语言。我在编码上很草率,并且知道脚本可以做得更好。

在动漫中,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/英文对整个国家

评论

问题标题应反映代码的功能,因此我编辑了您的标题以反映代码。

当您在get_letter()中混合字母和eng_letter时,您的代码已损坏。

我已根据接受的答案codereview.stackexchange.com/questions/112016/…中的建议创建了脚本的更新版本。

我注意到您已将接受的答案切换为仅代码的答案。您可能应该考虑社区对此做法的看法。

@ 200_success我以为您可以在看到多个答案上的勾号时选择多个答案。我不知道它会切换答案。感谢您指出这一点。

#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_letterletter混合在get_letter()中–这是失败的,您可能在将代码复制粘贴到Code Review中时引入了这些错误...错误2:标点符号错误翻译–使用find时,找不到字母时返回-1,这是Python中的合法索引,因此很高兴在其中返回字符位置:b


请使用完整的变量名-在大多数情况下,应拼写诸如ent_wordeng_letterusr_txt之类的东西,例如entean_wordenglish_letteruser_text。从长远来看,它使每个人都更容易

命名主要是好的-如果扩展名称,则命名主要是好的。但是,我将常量设为UPPER_SNAKE_CASE以清楚地将其标识为常量

将完整字母设为常数–在代码中,您要执行很多lower()upper()。特别是当设置一个常数时,这是浪费的。在get_letter()中,它更容易理解,但是如果将常量用小写字母和大写字母加倍,则无需在任何地方调用

在紧凑块中添加垂直间距–您的get_letter()非常紧凑,而且很难阅读,并且将所有return语句混合在一起,很难看到实际情况。我的规则是在ifelifelseforwhile之前,有时在逻辑代码块之前添加空白行。还要注意,函数前面应该有两个空行

拆分,添加和剥离字符串会有点昂贵–大多数时候,您的代码都是这样做的。了解您的选择,然后选择最适合您的一种。重构代码时,我保留一个版本进行拆分,并且一个版本像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_barryupper()比原始代码快,但比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))