Исправление новых строк в CSV с помощью Perl Text :: CSV_XS - PullRequest
0 голосов
/ 17 декабря 2018

Я пытаюсь очистить некоторые 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бывает?

Спасибо

Ответы [ 2 ]

0 голосов
/ 19 декабря 2018

Возможно, вы сможете проанализировать данные без 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, в том числе в конце каждой строки.

0 голосов
/ 17 декабря 2018

Ваш пример ввода выглядит как неправильно сформированный 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...