Perl — регулярное выражение в CSV

следующая проблема:

У меня есть файл с разделителями, строки которого имеют 25 или 26 полей. Для всех строк с 25 полями мне нужно добавить пустую строку после 13-го поля, чтобы в ней также было 26 полей.

Старый:

Z|432651242|987654321|XYZ|Abc|DEFEF||Abc-De-Fg|18|33221|Qwerty|18.06.3213|abc||123|Tepp|11.07.4443|2|||||4433322342344||

Новый:

Z|432651242|987654321|XYZ|Abc|DEFEF||Abc-De-Fg|18|33221|Qwerty|18.06.3213|abc|||123|Tepp|11.07.4443|2|||||4433322342344||

Мне удалось отфильтровать строки, которые нужно изменить:

#!/usr/bin/perl
use strict;
use warnings;

my (@cols,$fieldLength,);
while(<>){
  @cols = split('\|', $_);
  $fieldLength=@cols;
  if ($fieldLength==25){
  print $_;
  }
}

Моя идея состояла в том, чтобы заменить разделитель "|" в 13-м случае с "||", но не смог этого сделать. Я пытался найти его в Google, но примеры не сработали для меня.

Может ли кто-нибудь помочь мне с этим, пожалуйста?

Я также был бы признателен за решение с использованием модуля CSV от CPAN.


person royskatt    schedule 05.08.2013    source источник
comment
Text::CSV будет безопаснее регулярного выражения...   -  person Lucas    schedule 06.08.2013
comment
Text::CSV — правильный инструмент для этой работы.   -  person Jonathan M    schedule 06.08.2013


Ответы (2)


Если вы можете с уверенностью предположить, что разделитель | никогда не появляется в данных поля, то вы можете использовать split и splice, но Text::CSV безопаснее.

#!/usr/bin/perl
use strict;
use warnings;

while (<>)
{
    my @cols = split /[|]/;
    if (scalar(@cols) == 25)
    {
        splice(@cols, 13, 0, '');
        $_ = join('|', @cols);
    }
    print;
}

Кажется, это дает желаемый результат. Данный входной файл:

Z|432651242|987654321|XYZ|Abc|DEFEF||Abc-De-Fg|18|33221|Qwerty|18.06.3213|abc||123|Tepp|11.07.4443|2|||||4433322342344||
Z|432651242|987654321|XYZ|Abc|DEFEF||Abc-De-Fg|18|33221|Qwerty|18.06.3213|abc|def|123|Tepp|11.07.4443|2|||||4433322342344||

(где вторая строка имеет def вместо пустого поля, чтобы вы могли точно видеть, где происходит вставка), вывод:

Z|432651242|987654321|XYZ|Abc|DEFEF||Abc-De-Fg|18|33221|Qwerty|18.06.3213|abc|||123|Tepp|11.07.4443|2|||||4433322342344||
Z|432651242|987654321|XYZ|Abc|DEFEF||Abc-De-Fg|18|33221|Qwerty|18.06.3213|abc||def|123|Tepp|11.07.4443|2|||||4433322342344||
person Jonathan Leffler    schedule 05.08.2013
comment
Спасибо, это сработало. Возможно, вы знаете, как будет выглядеть Text::CSV? - person royskatt; 06.08.2013
comment
Это будет более или менее похоже на код, показанный TLP в его ответ. - person Jonathan Leffler; 06.08.2013

Вы можете использовать Text::CSV для разбора строк, вставки пустой строки с склейкой и Распечатай. Что-то вроде этого должно работать:

use strict;
use warnings;
use Text::CSV;

my $csv = Text::CSV->new({
    sep_char => '|',
    eol      => $/,
});

while (my $row = $csv->getline(*ARGV)) {
    splice(@$row, 12, 0, '') if @$row == 25;
    $csv->print(*STDOUT, $row);
}
person TLP    schedule 05.08.2013
comment
Благодарю вас! Просто для любопытства, потому что я пытался, но это не сработало. Каким было бы решение регулярного выражения? - person royskatt; 06.08.2013
comment
Это было бы излишне сложно. - person TLP; 06.08.2013
comment
Вроде так, но я сначала не мог поверить, что может быть так сложно просто заменить n-е вхождение чего-то здесь. Я спрашиваю, потому что я не могу использовать модули там, где мне это нужно. - person royskatt; 06.08.2013
comment
@TLP: в фрагменте слишком много ошибок: построение не работает (параметры должны быть в хэшрефе, похоже), нет проверки or die Text::CSV->error_diag ();, скрипт не компилируется: $r, вероятно, должно быть $row. - person Slaven Rezic; 06.08.2013
comment
Я изменил $r на $row, но все еще получаю сообщение об ошибке: Невозможно использовать неопределенное значение в качестве ссылки на символ в .\correct.pl, строка 11. Это функция getline. - person royskatt; 06.08.2013
comment
@SlavenRezic Достаточно честно, я только что переписал это из одной строки, поэтому я пропустил некоторые вещи, теперь исправлено. Я сомневаюсь, что есть какая-либо реальная необходимость проверять, успешно ли мы создали объект csv с оператором die. - person TLP; 06.08.2013
comment
@user2557981 user2557981 Я сделал несколько ошибок при вводе кода. Хотя теперь это должно работать. - person TLP; 06.08.2013