处理不带双引号的 CSV 文件
Processing CSV file without double quotes
换句话说,我正在寻找一种方法来忽略其中一个字段中的“,”。
该字段应被视为一个单独的字段,即使它包含一个逗号。
示例:
Round,Winner,place,prize
1,xyz,1,,500
如果我用 dict reader 阅读这个 ,500
打印为 </code> 因为 <code>500
被认为是另一个字段。,这在我阅读时很有意义文件以逗号分隔,所以我真的不能抱怨,而是想办法解决。
reader = csv.reader(f, delimiter=',', quotechar='"')
我的来源没有用双引号引起来,所以我不能通过包含引号字符串来忽略它。
还有其他方法可以处理这种情况吗?可能类似于定义这些美元字段并使其忽略该字段的逗号?或者尝试在该字段周围插入引号?
如果不是 Python,可以使用 shell 脚本或 Perl 来完成吗?
如果额外的 ,
在存在时总是成为最后一个字段的一部分,您可以对其使用 Bash 读取循环:
#!/bin/bash
while IFS=, read -r f1 f2 f3 f4; do
# f4 => has everything after f3, including extra commas as in ,500
# do your processing
printf "f1=[$f1] f2=[$f2] f3=$[f3] f4=[$f4]\n"
done < input.txt
输入:
1,xyz,1,,500
2,abc,3,0
输出:
f1=[1] f2=[xyz] f3=1 f4=[,500]
f1=[2] f2=[abc] f3=3 f4=[0]
也许pre-process数据把所有的钱都用引号括起来,然后正常处理
$line =~ s/( $\d+ (?:,\d{3})* (?:\.\d{2})? )/""/gx;
该模式匹配 $
之后的数字,可选地后跟 ,nnn
and/or 的任意倍数 .nn
。它还包含 .22
和 0
,我认为这有利于一致性。如果需要,限制匹配的内容,例如 ($\d{1,3},\d{3})
。使用分数美分删除 {2}
。这并未涵盖所有可能的 edge/broken 个案例。
/g
修饰符使其替换行中的所有此类内容,并且 /x
允许空格以供阅读。
你可以像 one-liner
perl -pe 's/($\d+(?:,\d{3})*(?:\.\d{2})?)/""/g' input.csv > changed.csv
添加 -i
开关以覆盖输入 ("in-place"),或 -i.bak
也保留备份。
如果您预计需要进一步调整,或者为了更好地记录这一点,请将其放入脚本中
use warnings;
use strict;
my $file = '...';
my $fout = '...';
open my $fh, '<', $file or die "Can't open $file: $!";
open my $fh_out, '>', $fout or die "Can't open $fout for writing: $!";
while (my $line = <$fh>) {
$line =~ s/( $\d+ (?:,\d{3})* (?:\.\d{2})? )/""/gx;
print fh_out $line;
}
close $fh;
close $fh_out;
换句话说,我正在寻找一种方法来忽略其中一个字段中的“,”。
该字段应被视为一个单独的字段,即使它包含一个逗号。
示例:
Round,Winner,place,prize
1,xyz,1,,500
如果我用 dict reader 阅读这个 ,500
打印为 </code> 因为 <code>500
被认为是另一个字段。,这在我阅读时很有意义文件以逗号分隔,所以我真的不能抱怨,而是想办法解决。
reader = csv.reader(f, delimiter=',', quotechar='"')
我的来源没有用双引号引起来,所以我不能通过包含引号字符串来忽略它。
还有其他方法可以处理这种情况吗?可能类似于定义这些美元字段并使其忽略该字段的逗号?或者尝试在该字段周围插入引号?
如果不是 Python,可以使用 shell 脚本或 Perl 来完成吗?
如果额外的 ,
在存在时总是成为最后一个字段的一部分,您可以对其使用 Bash 读取循环:
#!/bin/bash
while IFS=, read -r f1 f2 f3 f4; do
# f4 => has everything after f3, including extra commas as in ,500
# do your processing
printf "f1=[$f1] f2=[$f2] f3=$[f3] f4=[$f4]\n"
done < input.txt
输入:
1,xyz,1,,500
2,abc,3,0
输出:
f1=[1] f2=[xyz] f3=1 f4=[,500]
f1=[2] f2=[abc] f3=3 f4=[0]
也许pre-process数据把所有的钱都用引号括起来,然后正常处理
$line =~ s/( $\d+ (?:,\d{3})* (?:\.\d{2})? )/""/gx;
该模式匹配 $
之后的数字,可选地后跟 ,nnn
and/or 的任意倍数 .nn
。它还包含 .22
和 0
,我认为这有利于一致性。如果需要,限制匹配的内容,例如 ($\d{1,3},\d{3})
。使用分数美分删除 {2}
。这并未涵盖所有可能的 edge/broken 个案例。
/g
修饰符使其替换行中的所有此类内容,并且 /x
允许空格以供阅读。
你可以像 one-liner
perl -pe 's/($\d+(?:,\d{3})*(?:\.\d{2})?)/""/g' input.csv > changed.csv
添加 -i
开关以覆盖输入 ("in-place"),或 -i.bak
也保留备份。
如果您预计需要进一步调整,或者为了更好地记录这一点,请将其放入脚本中
use warnings;
use strict;
my $file = '...';
my $fout = '...';
open my $fh, '<', $file or die "Can't open $file: $!";
open my $fh_out, '>', $fout or die "Can't open $fout for writing: $!";
while (my $line = <$fh>) {
$line =~ s/( $\d+ (?:,\d{3})* (?:\.\d{2})? )/""/gx;
print fh_out $line;
}
close $fh;
close $fh_out;