Regex для удаления новых строк, за которыми не следует конкретная строка - PullRequest
0 голосов
/ 18 января 2019

У меня есть файл данных с разделителями и вводом пользователя, который мне нужно очистить. В частности:

  1. В свободные текстовые поля встроены новые строки, которые я хочу удалить
  2. Количество столбцов может меняться от одной строки к следующей
  3. Первое поле каждой строки ДОЛЖНО ВСЕГДА начинаться с шаблона "INC\d{12}" (двойные кавычки являются частью шаблона).
  4. Каждый \n должен быть заменен одним пробелом, если за ним сразу не следует шаблон "INC\d{12}"
  5. В настоящее время я использую Perl (предпочтительно) в Cygwin, но также возможны ответы на awk или sed.

Вот некоторые фиктивные входные данные (я сохранил свой файл с именем test_input_so.txt):

"INC000111111111", "field2", "field3"

"INC000222222222", "field2", "field3","INC000123456789 blahblah"



"INC000444444444", "fie"""ld2", "field3"
"INC000123

456789", "field2", "field3",
"INC000333333333", "INC000123456789", "field3""
"INC000555555555", "field2", "fiel
d3","field4"

Вот требуемый вывод для вышеуказанных данных:

"INC000111111111", "field2", "field3"    
"INC000222222222", "field2", "field3","INC000123456789 blahblah"
"INC000444444444", "fie"""ld2", "field3"
"INC000123456789", "field2", "field3",
"INC000333333333", "INC000123456789", "field3""
"INC000555555555", "field2", "field3","field4"

Я пробовал несколько комбинаций отрицательных взглядов / зад, но я не уверен, почему это не работает.

Вот один пример:

perl -pe 's/\n(?!"INC\d{12})/ /g;' test_input_so.txt 

Удаляет все \n, но неправильно удаляет \n, за которым следует "INC123456789012", который должен оставить на месте.

Ответы [ 3 ]

0 голосов
/ 18 января 2019

Во-первых, у вас есть несколько случайных кавычек, которые нужно исправить, чтобы ваши данные могли быть действительными CSV:

  • строка 7: "fie"""ld2" должно быть "fie""ld2"
  • строка 11: заканчивается двумя двойными кавычками

Во-вторых, не ставьте пробел после запятой между полями: не a, b, а a,b

После того, как вы исправите эти вещи, вы можете использовать модуль Text :: CSV :

Я думаю, что вы действительно хотите сделать это удалить символы новой строки, которые находятся внутри указанных полей . Структура этого кода взята из perldoc Text :: CSV.

perl -MData::Dump=dd -E '
    use Text::CSV;
    my $csv = Text::CSV->new ({ binary => 1, always_quote => 1 })
                   or die "Cannot use CSV: ".Text::CSV->error_diag ();

    my $file = shift @ARGV;
    open my $fh, "<:encoding(utf8)", $file or die;
    while ( my $row = $csv->getline( $fh ) ) {
        my @row = map {s/\n//g; $_} @$row;
        $csv->combine(@row);
        my $line = $csv->string();
        say $line if $line ne q{""};
    }
    $csv->eof or $csv->error_diag();
    close $fh;
' test_input_so.txt
"INC000111111111","field2","field3"
"INC000222222222","field2","field3","INC000123456789 blahblah"
"INC000444444444","fie""ld2","field3"
"INC000123456789","field2","field3",""
"INC000333333333","INC000123456789","field3"
"INC000555555555","field2","field3","field4"
0 голосов
/ 19 января 2019

Другой Perl

$  perl -0777 -ne ' while( /(^"INC00.+?)(\n"INC.*|\Z)/msg ) { $x=$1;$_=$2; $x=~s/\n//g; print "$x\n" } ' test_input_so.txt
"INC000111111111", "field2", "field3"
"INC000222222222", "field2", "field3","INC000123456789 blahblah"
"INC000444444444", "fie"""ld2", "field3"
"INC000123456789", "field2", "field3",
"INC000333333333", "INC000123456789", "field3""
"INC000555555555", "field2", "field3","field4"
$

Введите:

$ cat test_input_so.txt
"INC000111111111", "field2", "field3"

"INC000222222222", "field2", "field3","INC000123456789 blahblah"



"INC000444444444", "fie"""ld2", "field3"
"INC000123

456789", "field2", "field3",
"INC000333333333", "INC000123456789", "field3""
"INC000555555555", "field2", "fiel
d3","field4"

$
0 голосов
/ 18 января 2019

perl -pe ... работает с одной строкой за раз, поэтому многострочное регулярное выражение вам не поможет.

Переключатель -0 на Perl может изменить ваш разделитель входных записей (что такое Perl для обозначения строки) и позволит вам работать со всем вводом как одной строкой.

perl -0777 -pe 's/\n(?!"INC\d{12})/ /g;' test_input_so.txt
...