【问题标题】:Fixing newlines within CSV with perl Text::CSV_XS使用 perl Text::CSV_XS 修复 CSV 中的换行符
【发布时间】:2019-05-17 21:27:51
【问题描述】:

我正在尝试清理一些没有转义的 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 替换为
吗?

谢谢

【问题讨论】:

  • 能否请edit您的帖子并在此处添加(相关)代码?链接到场外代码对给出好的答案没有多大帮助。

标签: perl csv


【解决方案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 中的所有换行符,包括每一行的末尾。

【讨论】:

  • 嗨,beasy,这实际上是一个不错的解决方案,因为我确定特定文件有多少列。然而 ;没有转义,因此对该字符的拆分不会导致正确的行为。一个非常困难的行可能是: "foo";"b"\nar";";"foobar"\n Yes... "b"\nar";";是 1 列...谁能解决这个问题?
  • 这可能是不可能的,除非你能识别出某种模式来区分列
【解决方案2】:

您的示例输入看起来像格式错误的 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 数据。

【讨论】:

  • 您好,感谢您的意见。不幸的是,我正在处理这种格式错误的 csv。我无法控制这些文件的来源,它们确实被引用了,但没有被转义。是的...没有逃脱...我知道尝试修复这些文件是一个漫长的过程..
  • 哦哇...是的,那是另一回事。您可能需要编写一些代码来清理数据。为此,您需要对数据有很多了解——有多少字段、数据类型等,并从中得出可能的值。我不羡慕这项任务。
猜你喜欢
  • 1970-01-01
  • 2018-10-29
  • 2013-01-24
  • 2013-05-17
  • 2020-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-02
相关资源
最近更新 更多