Python 创建符合标准的文件
我有一个逗号分隔的文件。线条看起来像这样Python 创建符合标准的文件,python,sed,awk,grep,Python,Sed,Awk,Grep,我有一个逗号分隔的文件。线条看起来像这样 1,2,3,4,5 6,7,8 9,10 11,12,13,14,15 我需要在所有行中有5列。所以新文件将是 1,2,3,4,5 6,7,8,, 9,10,,, 11,12,13,14,15 换句话说,如果一行中少于4个逗号。在末尾添加所需的数字。有人告诉我,有一个python模块也会做同样的事情。我在哪里可以找到这样的模块?awk是否更适合此类任务?您正在寻找的模块是。您仍然需要确保列表满足最小长度要求: with open('output.cs
1,2,3,4,5
6,7,8
9,10
11,12,13,14,15
我需要在所有行中有5列。所以新文件将是
1,2,3,4,5
6,7,8,,
9,10,,,
11,12,13,14,15
换句话说,如果一行中少于4个逗号。在末尾添加所需的数字。有人告诉我,有一个python模块也会做同样的事情。我在哪里可以找到这样的模块?awk是否更适合此类任务?您正在寻找的模块是。您仍然需要确保列表满足最小长度要求:
with open('output.csv', 'wb') as output:
input = csv.reader(open('faultyfile.csv', 'rb'))
output = csv.writer(output, dialect=input.dialect)
for line in input:
if len(line) < 5:
line.extend([''] * (5 - len(line)))
output.writerow(line)
以open('output.csv','wb')作为输出的:
输入=csv.reader(打开('faultyfile.csv','rb'))
输出=csv.writer(输出,方言=输入,方言)
对于行输入:
如果长度(线)<5:
行。扩展(['']*(5-列(行)))
output.writerow(第行)
如注释中所述,当您确实不需要时,它会将整个文件读入内存。要做到这一点,并非一蹴而就:
import shutil
def correct_file(fname):
with open(fname,'r') as fin, open('temp','w') as fout:
for line in fin:
new = line[:-1]+(4-line.count(','))*',' + '\n'
fout.write(new)
shutil.move('temp',fname)
这将使任何名为temp
的文件在当前目录中消失。当然,您可以始终使用tempfile
模块来解决这个问题
对于更详细但防弹的(?)版本:
import shutil
import tempfile
import atexit
import os
def try_delete(fname):
try:
os.unlink(fname)
except OSError:
if os.path.exists(fname):
print "Couldn't delete existing file",fname
def correct_file(fname):
with open(fname,'r') as fin, tempfile.NamedTemporaryFile('w',delete=False) as fout:
atexit.register(lambda f=fout.name: try_delete(f)) #Need a closure here ...
for line in fin:
new = line[:-1]+(4-line.count(','))*',' + '\n'
fout.write(new)
shutil.move(fout.name,fname) #This should get rid of the temporary file ...
如果您确定它将始终为n个项目长(在本例中为5),并且在打开文件之前您将始终知道。。。这样做内存效率更高
如果您不介意使用awk,那么它很简单:
$ cat data.txt
1,2,3,4,5
6,7,8
9,10
11,12,13,14,15
$ awk -F, 'BEGIN {OFS=","} {print $1,$2,$3,$4,$5}' data.txt
1,2,3,4,5
6,7,8,,
9,10,,,
11,12,13,14,15
这可能适用于您(GNU-sed):
如果您没有得到答案,请不要再提问模块是
csv
,尽管您可能需要手动填充您阅读的列表。@Minion91--这是不同的。以前OP只是想跳过格式错误的文件。这是关于更正它们的问题。这是为了一些代码挑战,不是吗?为什么要在再次写之前将所有内容读入内存?您可以轻松地逐行执行此操作。:-)@MartijnPieters——如果要避免使用shutil.move
来移动临时文件,则不需要。我想您可以使用tempfile
+shutil
安全地创建一个临时文件,然后将其移动,但是如果该文件足够小,可以放入内存,为什么不将其全部放在适当的位置?这会有什么问题呢?这些文件有多大?@MartijnPieters——没问题。它只是更复杂而已。@MartijnPieters——在内存中完成这一切的另一个好处是,如果读取过程中途中断,磁盘上就不会剩下一个处理了一半的文件。我想你可能会说,如果这个过程在写的中途中断,你就丢失了数据……为什么要在再次写之前把所有的东西都读入内存呢?您可以轻松地逐行执行此操作。:-)只是因为他说总是五点。。。这考虑到某些文件中可能有6或7个…您也提出了一个很好的观点。。。假设它总是5,并且在查看文件之前您总是知道这一点:)list(line.split(','))
是多余的。还有,为什么不使用listcomp呢rows=[line.split(',')表示f中的行]
?我的最后一条评论,print“\n.join([str(r)…])
——您可以省略方括号,只使用生成器。如果数据是以管道分隔的,而不是,如何定义它?从链接上找到的。非常感谢!如果在读取时使用分隔符=“^”,则在写入时它不使用相同的分隔符(扩展)?好的,在python中,如果您尝试一下,一切都会正常工作。明白了。输出csv.writer也需要被告知要使用什么分隔符。我已经稍微更新了代码,将输出csv.writer配置为与输入阅读器相同的方言。awk从未停止过,这让我感到惊讶。
with open('somefile.txt') as f:
rows = []
for line in f:
rows.append(line.split(","))
max_cols = len(max(rows,key=len))
for row in rows:
row.extend(['']*(max_cols-len(row))
print "\n".join(str(r) for r in rows)
with open("f1","r"):
with open("f2","w"):
for line in f1:
f2.write(line+(","*(4-line.count(",")))+"\n")
$ cat data.txt
1,2,3,4,5
6,7,8
9,10
11,12,13,14,15
$ awk -F, 'BEGIN {OFS=","} {print $1,$2,$3,$4,$5}' data.txt
1,2,3,4,5
6,7,8,,
9,10,,,
11,12,13,14,15
sed ':a;s/,/&/4;t;s/$/,/;ta' file