Исправление новых строк в CSV с помощью Perl Text :: CSV_XS

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

Спасибо

Не могли бы вы редактировать ваш пост и добавить сюда (соответствующий) код? Ссылки на сторонний код не очень помогают в получении хороших ответов.

Corion 17.12.2018 14:49
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
255
2

Ответы 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. Я не контролирую источник этих файлов, и они цитируются, но не экранируются. Да ... не удалось сбежать ... Я знаю, что попытки исправить эти файлы - долгая задача ...

Sam 18.12.2018 08:36

Ого ... Да, это другое дело. Возможно, вам потребуется написать код для очистки данных. Для этого вам нужно много знать о данных - сколько полей, типов данных и т. д., И получить из них возможные значения. Я не завидую задаче.

Hambone 18.12.2018 16:38

Вы могли бы проанализировать данные без 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 столбец ... Как это исправить?

Sam 21.12.2018 08:33

Это может быть невозможно, если вы не сможете определить какой-то шаблон, который позволяет вам различать столбцы.

beasy 21.12.2018 20:38

Другие вопросы по теме