我正在尝试清理一些没有转义的csv文件。
我没有perl经验,但是从Text :: CSV_XS的示例中刮了几行代码,但我设法得到了一个有效的脚本,除了未转义的换行符。
https://gist.github.com/samvdb/761d12cb6e0275105a689ce25765496d
#!/usr/bin/perl
# This script can be used as a base to parse unreliable CSV streams
# Modify to your own needs
#
# (m)'08 [23 Apr 2008] Copyright H.M.Brand 2008-2018
use strict;
use warnings;
sub usage {
my $err = shift and select STDERR;
print <<"EOH";
usage: $0 [-o file] [-s S] [file]
-o F --out=F output to file F (default STDOUT)
-s S --sep=S set input separator to S (default ; , TAB or |)
EOH
exit $err;
} # usage
use Getopt::Long qw(:config bundling);
GetOptions (
"help|?" => sub { usage (0); },
"s|sep=s" => \my $in_sep,
"o|out=s" => \my $opt_o,
) or usage (1);
use Text::CSV_XS qw( csv );
my $io = shift || \*DATA;
my $eol = "\n";
binmode STDOUT, ":encoding(utf-8)";
my @hdr;
my @opt_i = (
in => $io,
binary => 1,
blank_is_undef => 1,
allow_loose_quotes => 1,
allow_loose_escapes => 1,
sep => ";",
encoding => "utf16le",
);
my @opt_o = (out => \*STDOUT, eol => $eol, sep => ",", quo => '"', always_quote => 1,);
push @opt_i,
bom => 1,
sep_set => [ $in_sep ],
keep_headers => \@hdr;
push @opt_o,
headers => \@hdr;
csv (in => csv (@opt_i), @opt_o);
__END__
a;b;c;d;e;f
"test"and also newline\nhere or something";2;3;4;5;6
"this happens also! "\n here or something";2;3;4;5;6
2;3;4;5;6;7
3;4;5;6;7;8
4;5;6;7;8;9
示例输入:
a;b;c;d;e;f
"test"and also newline\nhere or something";2;3;4;5;6
"this happens also! "\n here or something";2;3;4;5;6
2;3;4;5;6;7
3;4;5;6;7;8
4;5;6;7;8;9
该行的预期结果:
"test""and also newline<br/>here or something";2;3;4;5;6
"this happens also! ""<br/> here or something";2;3;4;5;6
有人可以帮我修复此Perl脚本,以便将\ n替换为
吗?
谢谢
答案 0 :(得分:1)
如果您的分隔符(';')不需要转义,并且行中的列数是恒定的,则可以不用Text::CSV
来解析数据。然后,您可以根据需要进行清理。但是,您将需要了解一些Perl以根据您的特定需求清理单元。
use strict;
use warnings;
# slurp file into a string and split it
open my $fh,'<',$ARGV[0];
$/ = undef;
my @data = split ';', <$fh>;
my $columns = 6;
my @new_data;
# splice 6 elements from the array at a time until the array is out of elements
while (@data) {
my @row = splice @data, 0, $columns;
for my $cell (@row) {
# inspect / clean up $cell
}
push @new_data, \@row;
}
for my $row (@new_data) {
print join(';', @$row)."\n";
}
并不是说这会保留$cell
中的所有换行符,包括每一行的末尾。
答案 1 :(得分:0)
您的示例输入看起来像格式不正确的CSV格式-我认为您列出的内容无法解析为正确的CSV。例如:
"test"and also newline\nhere or something";2;3;4;5;6
"this happens also! "\n here or something";2;3;4;5;6
数据周围的“引号”表示其中包含的所有内容可能都有特殊字符(定界符,换行符等),但是当您在此处关闭引号时:
"test"and also newline\nhere or something";2;3;4;5;6
^
你打破了。要嵌入报价,您需要添加两个引号。格式正确:
"test""and also newline\nhere or something";2;3;4;5;6
假设实际(渲染的)文本为test" and also...
如果我了解您要做什么,请用HTML换行符替换换行符,我认为这可以解决问题:
use Text::CSV_XS qw(csv);
my @rows;
my $csv = Text::CSV_XS->new({
binary => 1,
auto_diag => 1,
sep_char => ';'
});
open my $IN, '<:encoding(utf8)', "test.csv" or die;
open my $OUT, '>:encoding(utf8)', "new.csv" or die;
while (my $row = $csv->getline($IN)) {
s/\n/<br>/g for @$row;
$csv->print ($OUT, $row);
print $OUT "\n";
}
close $OUT;
close $IN;
如果这是示例输入:
a;b;c;d;e;f
"test""ja ze";2;3;4;5;6
2;3;"This Text has
a newline";5;6;7
3;4;5;6;7;8
4;5;6;7;8;9
这将是输出:
a;b;c;d;e;f
"test""ja ze";2;3;4;5;6
2;3;"This Text has<br>a newline";5;6;7
3;4;5;6;7;8
4;5;6;7;8;9
但同样,这些都假设格式正确的CSV数据。