《Python编程快速上手——让繁琐工作自动化 第2版》
6.8 项目 小程序:Pig Latin
简介
Pig Latin 是一种傻乎乎的、可伪造的语言, 它会改变英语单词。如果单词以元音开头,就在单词末尾添加yay。如果单词以辅音或辅音簇(例如ch或gr)开头,那么该辅音或辅音簇会移至单词的末尾,然后加上ay
让我们编写一个Pig Latin 程序,该程序将输入如下内容:
Enter the English message to translate into Pig Latin:
My name is AL SWEIGART and I am 4,000 years old.
Ymay amenay isyay ALYAY EIGARTSWAY andyay Iyay amyay 4,000 yearsysy oldyay.
该程序的工作原理是用本章介绍的方法更改字符串。在文件编辑器中输入以下源代码,并将文件另存为pigLatin.py:
(以下是书中提供的源代码,手敲版)
# English to Pig Latin
print('Enter the English message to translate into Pig Latin:')
message = input()
VOWELS = ('a', 'e', 'i', 'o', 'u', 'y')
pigLatin= [] # A list of the words in Pig Latin.
for word in message.split():
# Separate the non-letters at the start of this word:
prefixNonLetters = ''
while len(word) > 0 and not word[0].isalpha():
prefixNonLetters += word
word = word[1:]
if len(word) == 0:
pigLatin.append(prefixNonLetters)
continue
# Separate the non-letters at the end of this word:
suffixNonLetters = ''
while not word[-1].isalpha():
suffixNonLetters += word[-1]
word = word[:-1]
# Remember if the word was in uppercase or title case.
wasUpper = word.isupper()
wasTitle = word.istitle()
word = word.lower() # Make the word lowercase for translation.
# Separate the consonants at the start of this word:
prefixConsonants = ''
while len(word) > 0 and not word[0] in VOWELS:
prefixConsonants += word[0]
word = word[1:]
# Add the Pig Latin ending to the word:
if prefixConsonants != '':
word += prefixConsonants + 'ay'
else:
word += 'yay'
# Set the word back to uppercase or title case:
if wasUpper:
word = word.upper()
if wasTitle:
word = word.title()
# Add the non-letters back to the start or end of the word.
pigLatin.append(prefixNonLetters + word + suffixNonLetters)
# Join all the words back together into a single string:
print(' '.join(pigLatin))
代码添加中文注释
更新后代码:
# English to Pig Latin
print('Enter the English message to translate into Pig Latin:')
message = input()
VOWELS = ('a', 'e', 'i', 'o', 'u', 'y')
pigLatin = [] # A list of the words in Pig Latin.
for word in message.split():
# 提取某单词开头部分的非字母字符,并将该单词赋值为提取之后的单词
# Separate the non-letters at the start of this word:
prefixNonLetters = ''
while len(word) > 0 and not word[0].isalpha():
prefixNonLetters += word
word = word[1:]
# 如果提取某单词开头部分的非字母字符之后,该单词长度为空(即该单词只由非字母字符组成),将该单词直接添加到pigLatin列表
if len(word) == 0:
pigLatin.append(prefixNonLetters)
continue
# 提取某单词结尾部分的非字母字符,并将该单词赋值为提取之后的单词,赋值时注意保留原字符顺序。
# Separate the non-letters at the end of this word:
suffixNonLetters = ''
while not word[-1].isalpha():
suffixNonLetters += word[-1]
word = word[:-1]
# 用变量标记该单词是纯大写还是标题格式,剩下的默认均为小写
# Remember if the word was in uppercase or title case.
wasUpper = word.isupper()
wasTitle = word.istitle()
# 将单词均变为小写进行操作
word = word.lower() # Make the word lowercase for translation.
# 从单词开头分离所有的辅音字母
# Separate the consonants at the start of this word:
prefixConsonants = ''
while len(word) > 0 and not word[0] in VOWELS:
prefixConsonants += word[0]
word = word[1:]
# 判断是否含有辅音字符,把 Pig Latin 格式的后缀添加到单词中
# Add the Pig Latin ending to the word:
if prefixConsonants != '':
word += prefixConsonants + 'ay'
else:
word += 'yay'
# 判断纯大写和标题格式变量进行还原单词大小写状态
# Set the word back to uppercase or title case:
if wasUpper:
word = word.upper()
if wasTitle:
word = word.title()
# 添加修改后的单词到pigLatin列表中
# Add the non-letters back to the start or end of the word.
pigLatin.append(prefixNonLetters + word + suffixNonLetters)
# 将pigLatin列表用join()方法连接
# Join all the words back together into a single string:
print(' '.join(pigLatin))
代码优化
1.对于大小写判断的过程不够严谨,如'iPhone'、'驼峰命名法 (Camel Case)的使用情况,如MyClassName'等。
解决方法:将书中给出的元音元组VOWELS修改为大小写的字母,删除upper和title格式的判断和还原
优化前:
Enter the English message to translate into Pig Latin:
I have an iPhone, ane it's name is MyFirstPhone.
Iyay avehay anyay iphoneyay, aneyay it'syay amenay isyay yfirstphonemay.
优化后:
Enter the English message to translate into Pig Latin:
I have an iPhone, ane it's name is MyFirstPhone.
Iyay avehay anyay iPhoneyay, aneyay it'syay amenay isyay yFirstPhoneMay.
2.在计算 suffixNonLetters时,按照源代码,在某单词最后的非字母字符在重组后会是倒序,如下方代码,'T-800!' 的 '-800!' 重组后变为了 '!008-',与书中本意不符
解决方法:由于是从word[-1]开始提取,直接用+=会导致提取后的单词结尾部分的非字母字符顺序为逆序,所以使用正常字符串连接的方法
优化前:
Enter the English message to translate into Pig Latin:
I am T-800!
Iyay amyay Tay!008-
优化后:
Enter the English message to translate into Pig Latin:
I am T-800!
Iyay amyay Tay-800!
优化后代码:
# English to Pig Latin
print('Enter the English message to translate into Pig Latin:')
message = input()
VOWELS = ('a', 'e', 'i', 'o', 'u', 'y', 'A', 'E', 'I', 'O', 'U', 'Y')
pigLatin = [] # A list of the words in Pig Latin.
for word in message.split():
# 提取某单词开头部分的非字母字符,并将该单词赋值为提取之后的单词
# Separate the non-letters at the start of this word:
prefixNonLetters = ''
while len(word) > 0 and not word[0].isalpha():
prefixNonLetters += word
word = word[1:]
# 如果提取某单词开头部分的非字母字符之后,该单词长度为空(即该单词只由非字母字符组成),将该单词直接添加到pigLatin列表
if len(word) == 0:
pigLatin.append(prefixNonLetters)
continue
# 提取某单词结尾部分的非字母字符,并将该单词赋值为提取之后的单词,赋值时注意保留原字符顺序。
# 由于是从word[-1]开始提取,直接用+=会导致提取后的单词结尾部分的非字母字符顺序为逆序,所以使用正常字符串连接的方法
# Separate the non-letters at the end of this word:
suffixNonLetters = ''
while not word[-1].isalpha():
suffixNonLetters = word[-1] + suffixNonLetters
word = word[:-1]
# 从单词开头分离所有的辅音字母
# Separate the consonants at the start of this word:
prefixConsonants = ''
while len(word) > 0 and not word[0] in VOWELS:
prefixConsonants += word[0]
word = word[1:]
# 判断是否含有辅音字符,把 Pig Latin 格式的后缀添加到单词中
# Add the Pig Latin ending to the word:
if prefixConsonants != '':
word += prefixConsonants + 'ay'
else:
word += 'yay'
# 添加修改后的单词到pigLatin列表中
# Add the non-letters back to the start or end of the word.
pigLatin.append(prefixNonLetters + word + suffixNonLetters)
# 将pigLatin列表用join()方法连接
# Join all the words back together into a single string:
print(' '.join(pigLatin))
总结
1.该项目是在书中给出的VOWELS元音元组('a', 'e', 'i', 'o', 'u', 'y')的基础上编写的,解释是:元音字母包括:a, e, i, o, u。在某些语言中,y 也可以作为元音字母。
但实际上还有部分特殊情况,像 honor 、honest这样的单词中,尽管开头的字母是 h,但在发音上,h 不发音,实际发出的元音声音是由后面的字母 o 产生的。在这种情况下,尽管字母 h 处于单词开头,但实际发出的元音声音由后面的字母提供。
该脚本按照书中给出的元音元组来即可,暂时不对发音上的特殊情况进行处理。
2.Pig Latin的核心在于改变英语单词,但该脚本对复合词没有作处理,导致复合词的某一部分未被改变,如形容词复合词:Well-known(著名的)、High-quality(高质量的)、Old-fashioned(过时的),在'old-fashioned'改变为'old-fashionedyay'的过程中,'old'并未被改变。
在网络上没有找到严格的定义是否应改变为'oldyay-ashionedfay'的格式,所以暂时不对该情况进行处理了
Enter the English message to translate into Pig Latin:
Her well-known book on high-quality craftsmanship is considered a classic in the field, although some people find its approach a bit old-fashioned.
erHay ell-knownway ookbay onyay igh-qualityhay aftsmanshipcray isyay onsideredcay ayay assicclay inyay ethay ieldfay, althoughyay omesay eoplepay indfay itsyay approachyay ayay itbay old-fashionedyay.