Я пытаюсь очистить некоторые файлы 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 на
?
Спасибо
Ваш образец ввода выглядит как искаженный 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. Я не контролирую источник этих файлов, и они цитируются, но не экранируются. Да ... не удалось сбежать ... Я знаю, что попытки исправить эти файлы - долгая задача ...
Ого ... Да, это другое дело. Возможно, вам потребуется написать код для очистки данных. Для этого вам нужно много знать о данных - сколько полей, типов данных и т. д., И получить из них возможные значения. Я не завидую задаче.
Вы могли бы проанализировать данные без 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 Да ... "b" \ nar ";"; это 1 столбец ... Как это исправить?
Это может быть невозможно, если вы не сможете определить какой-то шаблон, который позволяет вам различать столбцы.
Не могли бы вы редактировать ваш пост и добавить сюда (соответствующий) код? Ссылки на сторонний код не очень помогают в получении хороших ответов.