2012-05-17 5 views
2

Мне нужна ваша профессиональная помощь в исправлении этого регулярного выражения с помощью perl?Нужна помощь в исправлении этого регулярного выражения с помощью Perl?

У меня есть этот файл данных ...

__Data__ 
SCSI - test-A 
ccccccccccccccccc 
aaaaaaaaaaaaaaaaa 
bbbbbbbbbbbbbbbbb 

__Data__ 
SCSI - test-B 
ccccccccccccccccc 
aaaaaaaaaaaaaaaaa 
bbbbbbbbbbbbbbbbb 

__Data__ 
SCSI - test-C 
ccccccccccccccccc 
aaaaaaaaaaaaaaaaa 
bbbbbbbbbbbbbbbbb

Я хотел бы следующий вывод

__Data__ 
SCSI - test-A 

__Data__ 
SCSI - test-B 

__Data__ 
SCSI - test-C

Вместо этого, я получаю этот выход, который отсутствует в __Data__ для двух данных записей.

__Data__ 
SCSI - test-A 
SCSI - test-B 
SCSI - test-C

Вот код ..

$/ = "__Data__"; # setting the input separator variable to __Data__ 

while(<ReadFile>) 
{ 
    $_ =~ s/(SCSI.*test-(A|B|C)?)(.*)/$1/ms; 
    print $_; 
} 

ответ

0

Попробуйте добавить

$\ = $/; 

... чтобы установить выходной разделитель записей, а также.

Однако, вы в конечном итоге с окончательным, паразитным экземпляром __Data__ в этом пути, так как это напечатано после каждой записи (в конце каждого print).

В качестве альтернативы, можно разделить на вход себя:

while (<ReadFile>) 
    { chomp; 
     next unless $_ eq '__Data__'; print; 
     my $next = <ReadFile>; 
     $next =~ s/(SCSI.*text-(A|B|C)?).*/$1/ms; 
     print $next; 
    } 
+0

спасибо BRPocock, ваше предложение frist прекрасно работает, но отображается дополнительная __Data__. –

0

Установите входной разделитель записей в пустую строку, чтобы включить режим абзаца. Добавьте новые строки в печать.

$/ = ""; # paragraph mode 

while (<ReadFile>) { 
    $_ =~ s/(SCSI.*test-(A|B|C))(.*)/$1/s; 
    print "$_\n\n"; 
} 
+0

Ваше решение работает, но я читаю множество записей данных, начиная с __Data__. Требуется ли для вашего решения мигающее пространство между каждой записью? –

+0

@JosephWalker: Да, это так. Проблема заключается в ваших записях/запуске/с данными, но разделитель входных записей - это то, что/завершает/запись. – choroba

2

Вы хотите сказать, что Perl, что строки заканчиваются __DATA__, так что вы получаете

1: "__Data__" 
2: "\nSCSI - test-A\nccc\naaa\nbbb\n\n__Data__" 
3: "\nSCSI - test-B\nccc\naaa\nbbb\n\n__Data__" 
4: "\nSCSI - test-C\nccc\naaa\nbbb\n" 

Но вы неправильно думать, что вы получите

1: "__Data__\nSCSI - test-A\nccc\naaa\nbbb\n\n" 
2: "__Data__\nSCSI - test-B\nccc\naaa\nbbb\n\n" 
3: "__Data__\nSCSI - test-C\nccc\naaa\nbbb\n" 

Решение:

my $after_data = 0; 
while (<>) { 
    if (/^__Data__$/) { 
     print; 
     $after_data = 1; 
    } 
    elsif ($after_data) { 
     print; 
     print "\n"; 
     $after_data = 0; 
    } 
} 

Вы также можете использовать режим пункта:

local $/ = ''; 
while (<>) { 
    print /^(.*\n.*\n)/; 
    print "\n"; 
} 
+0

спасибо за полезное техническое объяснение –

0

Вы, кажется, хочет печатать строки, которые соответствуют один из три категории.

  1. __Data__ маркеры
  2. тест линии SCSI
  3. пустые строки

режим пункт в Perl удобен, когда он работает, но это хрупкое. Пункты завершаются точно последовательностью "\n\n", но редакторы, которые не отображают пробелы, могут сделать это сложным для отладки, когда у вас есть пустая, но не пустая строка после абзаца.

Как указано в вашем вопросе, приведенный ниже код производит требуемый результат.

#! /usr/bin/env perl 

use strict; 
use warnings; 
use 5.10.0; # smart matching 

*ARGV = *DATA; # for demo only 

my @interesting_line = (qr/^__Data__/, qr/SCSI - test-/, qr/^\s*$/); 

while (<>) { 
    print if $_ ~~ @interesting_line; 
    print "\n" if eof && !eof(); 
} 

__DATA__ 
__Data__ 
SCSI - test-A 
ccccccccccccccccc 
aaaaaaaaaaaaaaaaa 
bbbbbbbbbbbbbbbbb 

__Data__ 
SCSI - test-B 
ccccccccccccccccc 
aaaaaaaaaaaaaaaaa 
bbbbbbbbbbbbbbbbb 

__Data__ 
SCSI - test-C 
ccccccccccccccccc 
aaaaaaaaaaaaaaaaa 
bbbbbbbbbbbbbbbbb 

В реальном использовании, вы должны удалить строку, отмеченную для демонстрации только, а затем предоставить один или несколько файлов данных в командной строке. Забавно выглядящий тест if eof && !eof() пытается определить, когда нужно вставлять дополнительные разделители между записями. Если вы хотите, чтобы это было правильно, вам нужно быть более преднамеренным.

Ниже приведен пример ввода нескольких файлов.

$ cat input1 
__Data__ 
SCSI - test-A 
ccccccccccccccccc 
aaaaaaaaaaaaaaaaa 
bbbbbbbbbbbbbbbbb 

__Data__ 
SCSI - test-B 
ccccccccccccccccc 
aaaaaaaaaaaaaaaaa 
bbbbbbbbbbbbbbbbb 

$ cat input2 
__Data__ 
SCSI - test-C 
ccccccccccccccccc 
aaaaaaaaaaaaaaaaa 
bbbbbbbbbbbbbbbbb 

$ ./extract-tests input1 input2 
__Data__ 
SCSI - test-A 

__Data__ 
SCSI - test-B 

__Data__ 
SCSI - test-C
Смежные вопросы