【问题标题】:Remove the newline character in a list read from a file [duplicate]删除从文件读取的列表中的换行符[重复]
【发布时间】:2011-05-18 04:21:51
【问题描述】:

我有一个简单的程序,它获取一个 ID 号并打印与该 ID 匹配的人的信息。信息存储在 .dat 文件中,每行一个 ID 号。

问题是我的程序也在从文件中读取换行符 \n 。我已经尝试过 'name'.split() 方法,但这似乎不适用于列表。

我的程序:

from time import localtime, strftime

files = open("grades.dat")
request = open("requests.dat", "w")
lists = files.readlines()
grades = []

for i in range(len(lists)):
    grades.append(lists[i].split(","))

cont = "y"

while cont == "y" or cont == "Y":
    answer = raw_input("Please enter the Student I.D. of whom you are looking: ")
    for i in range(len(grades)):
        if answer == grades[i][0]:
            print grades[i][1] + ", " + grades[i][2] + (" "*6) + grades[i][0] + (" "*6) + grades[i][3]
            time = strftime("%a, %b %d %Y %H:%M:%S", localtime())
            print time
            print "Exams - " + grades[i][11] + ", " + grades[i][12] + ", " + grades[i][13]
            print "Homework - " + grades[i][4] + ", " + grades[i][5] + ", " + grades[i][6] + ", " + grades[i][7] + ", " +grades[i][8] + ", " + grades[i][9] + ", " + grades[i][10]
            total = int(grades[i][4]) + int(grades[i][5]) + int(grades[i][6]) + int(grades[i][7]) + int(grades[i][8]) + int(grades[i][9]) + int(grades[i][10]) + int(grades[i][11]) + int(grades[i][12]) + int(grades[i][13])
            print "Total points earned - " + str(total)
            grade = float(total) / 550
            grade = grade * 100
            if grade >= 90:
                print "Grade: " + str(grade) + ", that is equal to an A."
            elif grade >= 80 and grade < 90:
                print "Grade: " + str('%.2f' %grade) + ", that is equal to a B."
            elif grade >= 70 and grade < 80:
                print "Grade: " + str('%.2f' %grade) + ", that is equal to a C."
            elif grade >= 60 and grade < 70:
                print "Grade: " + str('%.2f' %grade) + ", that is equal to a D."
            else:
                print "Grade: " + str('%.2f' %grade) + ", that is equal to an F."
            request.write(grades[i][0] + " " + grades[i][1] + ", " + grades [i][2] +
                          " " + time)
            request.write("\n")


    print
    cont = raw_input("Would you like to search again? ")

if cont != "y" or cont != "Y":
    print "Goodbye."

【问题讨论】:

  • 成绩数据的格式是什么? ID, (first/last) name, (last/first) name, etc.我想知道提供一个不错的namedtuple解决方案。
  • 格式为ID, last, first, degree major, Grade 1,2,3,4,5,6,7,8,9,10。
  • 能否请您发布示例输入文件grades.dat

标签: python list newline


【解决方案1】:

str.strip() 返回一个删除了前导+尾随空格的字符串,.lstrip.rstrip 分别仅用于前导和尾随。

grades.append(lists[i].rstrip('\n').split(','))

【讨论】:

  • 它肯定可以在 linux 上运行,但是如果行尾是 CR+LF(Windows) 或只是 CR(Mac)?
  • .rstrip('\r\n'),或简单的.rstrip(),将两者都剥离。
  • 导入操作系统; endl = os.linesep; .strip(endl) 或 rstrip / lstrip... 这样您就不必担心操作系统了 :)。
【解决方案2】:

您可以使用strip() 函数删除尾随(和前导)空格;传递一个参数会让你指定哪个空格:

for i in range(len(lists)):
    grades.append(lists[i].strip('\n'))

看起来你可以简化整个块,因为如果你的文件每行存储一个 ID,grades 只是 lists 去掉换行符:

之前

lists = files.readlines()
grades = []

for i in range(len(lists)):
    grades.append(lists[i].split(","))

之后

grades = [x.strip() for x in files.readlines()]

(上面是list comprehension


最后,您可以直接遍历列表,而不是使用索引:

之前

for i in range(len(grades)):
    # do something with grades[i]

之后

for thisGrade in grades:
    # do something with thisGrade

【讨论】:

  • 谢谢。澄清一下,这是否意味着与我的 for i in range(len(lists)):grades.append(lists[i].split(",")) 循环一起使用或替换?
  • @Python 替换它;我编辑了答案
  • 我用您的第一个 After 代码替换了第一个 Before 代码,但在输入 ID 后,它只是打印一个空行,然后跳到“您想再次搜索吗?”。我做错了吗?
  • -1 教新手在需要 strip('\n') 时使用 strip()
  • @John 这个错误本身是微不足道的,这几乎就是 cmets 存在的原因;大多数人只会评论“注意strip() 将删除所有空格,而不仅仅是换行符;您可能想改用strip('\n')”。我说“你可以使用 strip() 函数来删除尾随(和前导)空格”,你是对的,我应该将 '\n' 传递给 strip(),但反对票是针对完全没有帮助的答案(参见否决工具提示)。我想如果你想对基本正确的答案投反对票并帮助提问者但有小错误,那是你的选择
【解决方案3】:

您实际上可以通过将整个文件作为单个长字符串读入内存来充分利用换行符,然后使用它们通过使用字符串 splitlines() 方法将其拆分到成绩列表中,默认情况下,删除他们在这个过程中。

with open("grades.dat") as file:
    grades = [line.split(",") for line in file.read().splitlines()]
...

【讨论】:

  • 这也是我的想法,哪种方法更快?
  • @joemaller:通常唯一可以确定的方法是用一些测试数据实际计时——这通常可以通过timeit 模块轻松完成——我认为我最近的修订会很有竞争力。
  • 不错的更新。我一直在使用with open() as f: f.read().split('\n'),但splitlines() 更干净、更明显。 timeit 很明显,我很懒...
  • @joemaller:在使用 python -mtimeit "[line for line in open('AV1611Bible.txt').read().splitlines()]" 的 4+ MB 测试文件上,FWIW .splitlines() 仅比 .split('\n') 快几毫秒。测试文件是圣经的一个版本,从here下载并解压。在将近 34,000 行的文件上几毫秒的时间并不重要,所以任何一个都可以。
  • @joemaller:str.splitlines() 方法除了稍微快一点之外,还使用了universal newlines 方法来分割行,而str.split('\n') 没有这样做,所以前者也更好,因为它独立于平台。
【解决方案4】:

以下是适当的 Python 风格的各种优化和应用,可让您的代码更加整洁。我使用csv 模块添加了一些可选代码,这比手动解析更理想。我还添加了一些 namedtuple 优点,但我不使用随后提供的属性。 namedtuple 各部分的名称不准确,您需要更正它们。

import csv
from collections import namedtuple
from time import localtime, strftime

# Method one, reading the file into lists manually (less desirable)
with open('grades.dat') as files:
    grades = [[e.strip() for e in s.split(',')] for s in files]

# Method two, using csv and namedtuple
StudentRecord = namedtuple('StudentRecord', 'id, lastname, firstname, something, homework1, homework2, homework3, homework4, homework5, homework6, homework7, exam1, exam2, exam3')
grades = map(StudentRecord._make, csv.reader(open('grades.dat')))
# Now you could have student.id, student.lastname, etc.
# Skipping the namedtuple, you could do grades = map(tuple, csv.reader(open('grades.dat')))

request = open('requests.dat', 'w')
cont = 'y'

while cont.lower() == 'y':
    answer = raw_input('Please enter the Student I.D. of whom you are looking: ')
    for student in grades:
        if answer == student[0]:
            print '%s, %s      %s      %s' % (student[1], student[2], student[0], student[3])
            time = strftime('%a, %b %d %Y %H:%M:%S', localtime())
            print time
            print 'Exams - %s, %s, %s' % student[11:14]
            print 'Homework - %s, %s, %s, %s, %s, %s, %s' % student[4:11]
            total = sum(int(x) for x in student[4:14])
            print 'Total points earned - %d' % total
            grade = total / 5.5
            if grade >= 90:
                letter = 'an A'
            elif grade >= 80:
                letter = 'a B'
            elif grade >= 70:
                letter = 'a C'
            elif grade >= 60:
                letter = 'a D'
            else:
                letter = 'an F'

            if letter = 'an A':
                print 'Grade: %s, that is equal to %s.' % (grade, letter)
            else:
                print 'Grade: %.2f, that is equal to %s.' % (grade, letter)

            request.write('%s %s, %s %s\n' % (student[0], student[1], student[2], time))


    print
    cont = raw_input('Would you like to search again? ')

print 'Goodbye.'

【讨论】:

  • -1 使用 strip() 而不是 strip('\n')
  • @John Machin:这是故意的,因为格式似乎是 CSV,并且字段中可能很容易有空格。 (就此而言,这就是我推荐csv 的原因。)(此外,当我对代码进行了如此多的改进时,-1 似乎有点过激!)
【解决方案5】:

您需要 String.strip(s[, chars]) 函数,该函数将去除空格字符或您在 chars 参数中指定的任何字符(例如 '\n')。

http://docs.python.org/release/2.3/lib/module-string.html

【讨论】:

  • -1 有三个原因:(1)它是string,而不是String(2)不推荐使用具有等效str方法的字符串函数(3)OP没有说他们使用的是 Python 的古董版本,因此您应该将他们参考当前生产版本的文档,2.7 和 3.1,而不是 2.3。
  • @John Machin:好点,所有。回答这个问题时我可能有点匆忙,我使用的各种语言往往会在我的脑海中融合在一起。不过,谢谢你解释了你为什么不给我投票。我很高兴有机会学习。
猜你喜欢
  • 2018-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-22
  • 2023-04-02
  • 2016-04-07
相关资源
最近更新 更多