【问题标题】:Read file in python separated by \n but ignore last \n在 python 中读取文件,以 \n 分隔,但忽略最后一个 \n
【发布时间】:2018-03-23 07:15:54
【问题描述】:

我有一个名为 list.txt 的文件,如下所示:

input1
input2
input3

我确定最后一行 (input3) 之后没有空行。然后我有一个 python 脚本,它将逐行读取该文件并将文本写入更多文本以创建 3 个文件(每行一个):

import os
os.chdir("/Users/user/Desktop/Folder")

with open('list.txt','r') as f:
    lines = f.read().split('\n')

    #for l in lines:
        header = "#!/bin/bash \n#BSUB -J %s.sh \n#BSUB -o /scratch/DBC/user/%s.sh.out \n#BSUB -e /scratch/DBC/user/%s.sh.err \n#BSUB -n 1 \n#BSUB -q normal \n#BSUB -P DBCDOBZAK \n#BSUB -W 168:00\n"%(l,l,l)
        script = "cd /scratch/DBC/user\n"
        script2 = 'grep "input" %s > result.%s.txt\n'%(l,l)
        all= "\n".join([header,script,script2])

        with open('script_{}.sh'.format(l), 'w') as output:
            output.write(all)

我的问题是,这会创建 4 个文件,而不是 3 个:script_input1.sh、script_input.sh、script_input3.sh 和 script_.sh。最后一个文件没有文本,其他文件将有 input1 或 input2 或 input3。

似乎 Python 会逐行读取我的 list.txt,但是当它到达“input3”时,它会以某种方式继续吗?如何告诉 Python 逐行读取我的文件,以“\n”分隔,但在最后一个文本之后停止?

【问题讨论】:

标签: python bash for-loop newline


【解决方案1】:

使用您当前的方法,您需要:

  • 检查lines中的最后一个元素是否为空(lines[-1] == ''
  • 如果是这样,请将其丢弃 (lines = lines[:-1])。
with open('list.txt','r') as f:
    lines = f.read().split('\n')

if lines[-1] == '':
    lines = lines[:-1]

for line in lines:    
    print(line)

不要忘记文件不以换行符结尾(末尾有一个空行)是合法的......这将处理这种情况。


或者,正如@setsquare 指出的那样,您可能想尝试使用readlines()

with open('list.txt', 'r') as f:
    lines = [ line.rstrip('\n') for line in f.readlines() ]

for line in lines:
    print(line)

【讨论】:

  • 如果最后有多个空行怎么办?
  • 如果处理空行是一个问题,那么我们有一个不同的问题......这将只处理常见的“empty last line
【解决方案2】:

您是否考虑过使用 readlines() 代替 read()?这将让 Python 为您处理最后一行是否有 \n 的问题。

请记住,如果输入文件的最后一行确实有一个 \n,那么使用 read() 并用 '\n' 分割将创建一个额外的值。例如:

my_string = 'one\ntwo\nthree\n'
my_list = my_string.split('\n')
print my_list
# >> ['one', 'two', 'three', '']

可能的解决方案

lines = f.readlines()
# remove newlines
lines = [line.strip() for line in lines]
# remove any empty values, just in case
lines = filter(bool, lines)

一个简单的例子,看这里:How do I read a file line-by-line into a list?

【讨论】:

  • 为什么要使用readlines()lines = [line.strip() for line in f] 做同样的事情。但这并不能解决 OP 问题——你仍然需要过滤掉空行。
【解决方案3】:

首先,当您没有文件时不要将整个文件读入内存 - 文件是可迭代的,因此逐行读取文件的正确方法是:

with open("/path/to/file.ext") as f:
    for line in f:
        do_something_with(line)

现在在你的 for 循环中,你只需要删除该行,如果它是空的,忽略它:

with open("/path/to/file.ext") as f:
    for line in f:
        line = line.strip()
        if not line:
            continue
        do_something_with(line)

有点不相关,但 Python 有多行字符串,所以你也不需要连接:

# not sure I got it right actually ;)
script_tpl = """
#!/bin/bash 
#BSUB -J {line}.sh 
#BSUB -o /scratch/DBC/user/{line}.sh.out 
#BSUB -e /scratch/DBC/user/{line}.sh.err 
#BSUB -n 1 
#BSUB -q normal 
#BSUB -P DBCDOBZAK 
#BSUB -W 168:00
cd /scratch/DBC/user
grep "input" {line} > result.{line}.txt
"""

with open("/path/to/file.ext") as f:
    for line in f:
        line = line.strip()
        if not line:
            continue
        script = script_tpl.format(line=line)
        with open('script_{}.sh'.format(line), 'w') as output:
            output.write(script)

最后一点:避免更改脚本中的目录,使用os.path.join() 代替绝对路径。

【讨论】:

  • 感谢@bruno desthuilliers。关于您上一条评论的问题:在以下行中:“以 open('script_{}.sh'.format(l), 'w') 作为输出:”,我应该将“l”替换为“line”对吗?因为这个脚本中不再定义l
  • 最后一个问题,上面写着:“line = line.strip(); if not line:continue”的部分:是说:去掉空白行还是换行符?如果没有这样的空白或换行符继续?抱歉,我对 Python 很陌生,所以我不太清楚
  • str.strip() 删除所有前导和尾随空格(包括换行符),因此如果该行仅包含空格,它将返回一个空字符串。空字符串(以及空序列、字典和集合、数字零和无)在布尔上下文中具有错误值。所以我们删除所有空格,如果结果是一个空字符串,我们继续 tge 下一个(或者如果那是最后一行,则退出循环)。
  • 非常感谢您的解释!
【解决方案4】:

我认为你使用 split 错误。

如果您有以下情况:

text = 'xxx yyy'
text.split(' ') # or simply text.split()

结果是

['xxx', 'yyy']

现在如果你有:

text = 'xxx yyy ' # extra space at the end
text.split()

结果是

['xxx', 'yyy', '']

,因为 split 获取每个 ' ' (空格)之前和之后的内容。在这种情况下,最后一个空格后有一个空字符串。

你可能会用到的一些功能:

strip([chars]) # This removes all chars at the beggining or end of a string

例子:

text = '___text_about_something___'
text.strip('_')

结果将是:

'text_about_something'

在您的特定问题中,您可以简单地:

lines = f.readlines() # read all lines of the file without '\n'
for l in lines:
    l.strip(' ') # remove extra spaces at the start or end of line if you need

【讨论】:

    【解决方案5】:

    f.read() 返回一个以换行符结尾的字符串,split 尽职尽责地将最后一行与空字符串分开。目前尚不清楚为什么要将整个文件显式读入内存;只需遍历文件对象并让它处理分行。

    with open('list.txt','r') as f:
        for l in f:
            # ...
    

    【讨论】:

      猜你喜欢
      • 2011-04-29
      • 1970-01-01
      • 2019-07-02
      • 2023-01-25
      • 2018-11-04
      • 1970-01-01
      • 2011-05-06
      • 1970-01-01
      • 2015-09-07
      相关资源
      最近更新 更多