如何在Python中逐个读取字符串中的字符

13
我需要将用户输入的字符串转换为摩斯电码。我们教授要求我们从morseCode.txt文件中读取字母和其对应的摩斯电码并将它们分别存储到两个列表中,然后将每个字母转换为摩斯电码(在有空格的地方插入一个换行符)。
我已经完成了开始部分。我读取了morseCode.txt文件并将字母分别存储在列表[A,B,... Z]中,将摩斯电码存储在列表['- - . . - -\n','. - . - . -\n'...]中。
由于我们还没有学习“集合”,因此无法使用它。那么我该如何逐个字母地处理输入的字符串并将其转换为摩斯电码呢?我有些困惑。这是我目前的代码(很少......)
编辑:已经完成程序!
# open morseCode.txt file to read
morseCodeFile = open('morseCode.txt', 'r') # format is <letter>:<morse code translation><\n>   
# create an empty list for letters
letterList = []    
# create an empty list for morse codes
codeList = []
# read the first line of the morseCode.txt
line = morseCodeFile.readline()    
# while the line is not empty
while line != '':        
    # strip the \n from the end of each line
    line = line.rstrip()        
    # append the first character of the line to the letterList        
    letterList.append(line[0])           
    # append the 3rd to last character of the line to the codeList
    codeList.append(line[2:])        
    # read the next line
    line = morseCodeFile.readline()        
# close the file    
morseCodeFile.close()


try:
    # get user input
    print("Enter a string to convert to morse code or press <enter> to quit")    
    userInput = input("")  
    # while the user inputs something, continue   
    while userInput:
        # strip the spaces from their input
        userInput = userInput.replace(' ', '')
        # convert to uppercase
        userInput = userInput.upper()

        # set string accumulator
        accumulateLetters = ''
        # go through each letter of the word
        for x in userInput:            
            # get the index of the letterList using x
            index = letterList.index(x)
            # get the morse code value from the codeList using the index found above
            value = codeList[index]
            # accumulate the letter found above
            accumulateLetters += value
        # print the letters    
        print(accumulateLetters)
        # input to try again or <enter> to quit
        print("Try again or press <enter> to quit")
        userInput = input("")

except ValueError:
    print("Error in input. Only alphanumeric characters, a comma, and period allowed")
    main()   

4
我知道你的老师会鼓励你注释代码,但你也应该学会只在它们有用时使用它们;例如,文档化API、引用公式或数据表来源、解释为什么要以某种方式执行某些操作,即使似乎还有其他更简单的方法。 - fortran
考虑将try/except语句放在for x in inputLetters循环内部。这样,您就可以“接受”超出范围的字符,然后继续转换其余的所有字符。此外,您就不需要提前删除所有空格了。 - dash-tom-bang
谢谢大家的评论。Dash-tom-bang,我编辑了程序,通过将列表附加到它来允许空格。还有Fortran,但不幸的是,老师让我们先用伪代码编写程序,然后再回去用实际代码填写。所以如果某些地方没有注释,她会知道我们没有先写伪代码。我非常感谢你们的帮助! - dan
9个回答

21

为什么不直接遍历字符串?

a_string="abcd"
for letter in a_string:
    print letter

返回值

a
b
c
d

所以,用类似伪代码的方式,我会这样做:

user_string = raw_input()
list_of_output = []
for letter in user_string:
   list_of_output.append(morse_code_ify(letter))

output_string = "".join(list_of_output)

注意:函数morse_code_ify是伪代码。

绝对需要制作一个想要输出字符的列表,而不只是将它们连接在某个字符串的末尾。如上所述,这是O(n^2):很糟糕。只需将它们附加到列表上,然后使用"".join(the_list)

顺便说一下:为什么要移除空格?为什么不让morse_code_ify(" ")返回"\n"


4

有几件事情需要注意:

加载方式可以这样“优化”:

with file('morsecodes.txt', 'rt') as f:
   for line in f:
      line = line.strip()
      if len(line) > 0:
         # do your stuff to parse the file

这样你就不需要关闭,并且也不需要手动加载每一行等等。

for letter in userInput:
   if ValidateLetter(letter):  # you need to define this
      code = GetMorseCode(letter)  # from my other answer
      # do whatever you want

+1 这是很好的 Python 风格...学会这个,你将在你的课程和 Python 生活中节省很多代码。 - fitzgeraldsteele
1
len(line) 总是正数,因为它至少包含了行末字符。 - SilentGhost

2

我不能让这个问题留在这种状态下,带着那个问题中的最终代码悬而未决...

丹:这是你的代码的更简洁、更短的版本。以后看看这样做的方式,并更多地采用这种方式编码是一个好主意。我知道你可能不再需要这段代码了,但学习如何正确地编写代码是一个好主意。需要注意的一些事情:

  • 只有两个注释 - 即使第二个对于熟悉Python的人来说也不是必要的,他们会意识到NL被剥离了。只有在增加价值的情况下才编写注释。

  • with语句(在另一个答案中推荐)通过上下文处理程序消除了关闭文件的麻烦。

  • 使用字典代替两个列表。

  • 使用生成器表达式((x for y in z))在一行中进行翻译。

  • 尽可能少地将代码包装在try/except块中,以减少捕获意外异常的概率。

  • 使用input()参数而不是先print() - 使用'\n'获取所需的换行符。

  • 不要仅仅为了这样做而跨越多行或使用中间变量编写代码:

    a = a.b()
    a = a.c()
    b = a.x()
    c = b.y()
    

    相反,像这样编写这些结构,链接调用是完全有效的:

    a = a.b().c()
    c = a.x().y()
    

code = {}
with open('morseCode.txt', 'r') as morse_code_file:
    # line format is <letter>:<morse code translation>
    for line in morse_code_file:
        line = line.rstrip()  # Remove NL
        code[line[0]] = line[2:]

user_input = input("Enter a string to convert to morse code or press <enter> to quit\n")
while user_input:
    try:
        print(''.join(code[x] for x in user_input.replace(' ', '').upper()))
    except KeyError:
        print("Error in input. Only alphanumeric characters, a comma, and period allowed")

    user_input = input("Try again or press <enter> to quit\n")

2
# Retain a map of the Morse code
conversion = {}

# Read map from file, add it to the datastructure
morseCodeFile = file('morseCode.txt')
for line in moreCodeFile:
    conversion[line[0]] = line[2:]
morseCodeFile.close()

# Ask for input from the user
s = raw_input("Please enter string to translate")
# Go over each character, and print it the translation.
# Defensive programming: do something sane if the user 
# inputs non-Morse compatible strings.    
for c in s:
    print conversion.get(c, "No translation for "+c)

不能用这个,没学到这么多。我已经编辑了原帖以包含更多的代码。只需要帮忙完成它。 - dan
你目前的代码并没有真正起作用,所以很难“完成它”。你还没学到哪些部分? - moshez
我还没有学过映射。如果您查看我的编辑,为什么我不能使用循环遍历已去除空格的字符串,取出当前字母并在letterList列表中搜索其索引,然后使用相应位置在morseCode列表中查找莫尔斯电码,并返回该值。 - dan
哎呀,那就像是慢慢地编写自己的地图一样。你可以这么做,但是太可怕了。 [这与你目前的代码有关系无关,例如,“morseCodeFile.rstrip()”将失败。但我不确定“学习如何在Python中使用地图”的教育价值是否很大——地图是Python的灵魂...] - moshez
我修复了那个rstrip()行。现在是line = line.rstrip(),所以那不是问题。这太糟糕了 :( - dan

2
使用“index”。
def GetMorseCode(letter):
   index = letterList.index(letter)
   code = codeList[index]
   return code

当然,您需要验证输入字母(必要时转换其大小写,并通过检查索引!= -1 确保它在列表中),但这应该可以帮助您走上正确的道路。

+1 不仅是为了回答问题,还因为以一种方式回答问题,迫使提问者真正独立完成项目。 - acrosman

1
# Open the file
f = open('morseCode.txt', 'r')

# Read the morse code data into "letters" [(lowercased letter, morse code), ...]
letters = []
for Line in f:
    if not Line.strip(): break
    letter, code = Line.strip().split() # Assuming the format is <letter><whitespace><morse code><newline>
    letters.append((letter.lower(), code))
f.close()

# Get the input from the user
# (Don't use input() - it calls eval(raw_input())!)
i = raw_input("Enter a string to be converted to morse code or press <enter> to quit ") 

# Convert the codes to morse code
out = []
for c in i:
    found = False
    for letter, code in letters:
        if letter == c.lower():
            found = True
            out.append(code)
            break

    if not found: 
        raise Exception('invalid character: %s' % c)

# Print the output
print ' '.join(out)

1

对于实际处理,我会保留一个已完成产品的字符串,并循环遍历用户输入的每个字母。我会调用一个将字母转换为莫尔斯码的函数,然后将其添加到现有莫尔斯码字符串中。

finishedProduct = []
userInput = input("Enter text")
for letter in userInput:
    finishedProduct.append( letterToMorseCode(letter) )
theString = ''.join(finishedProduct)
print(theString)

你可以在循环中或被调用的函数中检查空格。

没问题,我只是在将字符串分割成单个字母时遇到了麻烦。 - dan
在Python中以那种方式构建字符串是个坏主意,因为它的时间复杂度是O(N**2)。应该先构建一个列表,然后使用"".join(l)将其连接起来,最后再打印出来。 - moshez

1
首先创建一个查找表:
morse = [None] * (ord('z') - ord('a') + 1)
for line in moreCodeFile:
    morse[ord(line[0].lower()) - ord('a')] = line[2:]

然后使用表格进行转换:

for ch in userInput:
    print morse[ord(ch.lower()) - ord('a')]

哎呀,不要更改range的返回值——它可能有效,但这并不是真正支持或良好风格的。如果您想要一个给定长度的列表, morse = [None] * (ord('z') - (ord('a')))会更好地工作。 - moshez

0
这是一个简单的例子: 这个程序计算一个句子中有多少个空格。
# get an input from the user  
inp = input("Write a sentence: ")
spaces = 0
for i in inp:
#print each letter the user have typed
     if(i == " ")
          spaces += 1
print(spaces)
    

1
这个例子和问题毫无关系,已经有几个答案展示了如何遍历句子中的字母。请阅读[答案],确保你发布的答案实际上解决了被问的问题。如果你的答案已经被提供,请不要再次发布。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接