我有一个如下所示的 csv 文件:
1,'someval','otherval',,,,,
'','someotherval','some_otherval',,,,,
1BSD,'',,,,,
2,'val',,,,,
,,,,,,
2BSD,,,,,,
2BCD,,,,,,
现在,每当新行的第一列是整数值时,我就想要拆分文件。
因此,对于上述 csv 输入,我必须获取 2 个包含以下内容的新文件:
1,'someval','otherval',,,,,
,'someotherval','some_otherval',,,,,
1BSD,'val',,,,,
和
2,'val',,,,,
,,,,,,
2BSD,,,,,,
2BCD,,,,,,
分别。
如何使用 Bash 和/或 Python 实现此目的?谢谢。
答案1
您可以使用该csplit
实用程序按正则表达式进行拆分,例如
csplit -z file.csv '/^[0-9]\+,/' '{*}'
80
42
(计数表示输出到每个文件的字符数 - 您可以通过添加选项来抑制它们-s
)。
输出文件默认命名xx00
为xx01
等 - 如果您愿意,可以选择更改前缀和后缀。
前任。
$ csplit -z file.csv '/^[0-9]\+,/' '{*}'
80
42
$ head xx*
==> xx00 <==
1,'someval','otherval',,,,,
'','someotherval','some_otherval',,,,,
1BSD,'',,,,,
==> xx01 <==
2,'val',,,,,
,,,,,,
2BSD,,,,,,
2BCD,,,,,,
答案2
我想看看我能用 做多少这样的事情sed
,而且我确实做到了相当多。我们可以sed
使用w
和W
命令写入文件,但我想不出在sed
循环的每次迭代中写入不同文件的方法,所以我不得不使用 shell 循环。sed
可能不是适合这项工作的工具,使用 可能有更好的方法sed
。无论如何,这就是我想出的办法:
#!/bin/bash
sed ':a;N;s/\n/\x00/; ta' input | sed -r 's/\x00([0-9]+(,|\x00|$))/\n\1/g' > edited
n=0
while [ -s edited ]; do
((n++))
sed -n '1p' edited > csv-"$n"
sed -i '1d' edited
done
sed -i 'y/\x00/\n/' csv-*
rm edited
评论
\x00
使用循环将换行符替换为空字符sed
。这样我们以后就可以使用换行符作为有意义的分隔符。sed ':a;N;s/\n/\x00/; ta' input
通过管道传输结果并在第一个字段的整数前添加换行符,然后将结果写入文件,
edited
| sed -r 's/\x00([0-9]+(,|\x00|$))/\n\1/g' > edited
初始化变量以增加
n=0
只要
edited
不空,做事while [ -s edited ]; do
增量
n
((n++))
将 的第一行写入
edited
新文件csv-$n
,其中$n
是 的当前值n
sed -n '1p' edited > csv-"$n"
删除第一行
edited
sed -i '1d' edited
这是循环的结束,因为我们要写入的每个文件只有一行,所以这并不像在循环中处理原始文件的每一行那么慢,但仍然很慢!
对于我们创建的每个文件,将空字符重新转换为换行符
sed -i 'y/\x00/\n/' csv-*
删除中间文件
rm edited