Как я могу пропустить некоторый контент блока при чтении в Perl - PullRequest
1 голос
/ 03 июня 2010

Я планирую пропустить содержимое блока, включающее начальную строку "MaterializeU4 ()" с подпрограммой () read_block ниже. Но не удалось.

# Read a constant definition block from a file handle. 
# void return when there is no data left in the file. 
# Otherwise return an array ref containing lines to in the block.  
sub read_block { 
    my $fh = shift; 

    my @lines; 
    my $block_started = 0; 

    while( my $line = <$fh> ) { 

    # how to correct my code below? I don't need the 2nd block content.
 $block_started++ if ( ($line =~ /^(status)/) && (index($line, "MaterializeU4") != 0) ) ;

 if( $block_started ) { 

     last if $line =~ /^\s*$/; 

     push @lines, $line; 
 }

    } 
    return \@lines if @lines;
    return; 
} 

Данные, как показано ниже:

__DATA__ 
status DynTest = <dynamic 100>
vid = 10002
name = "DynTest"
units   = ""

status VIDNAME9000 = <U4 MaterializeU4()>
vid = 9000
name = "VIDNAME9000"
units = "degC"

status DynTest = <U1 100>
vid = 100
name = "Hello"
units   = ""

Выход:

  <StatusVariables>
    <SVID logicalName="DynTest" type="L" value="100" vid="10002" name="DynTest" units=""></SVID>
    <SVID logicalName="DynTest" type="L" value="100" vid="100" name="Hello" units=""></SVID>
  </StatusVariables>

[Обновлено] Я печатаю значение index($line, "MaterializeU4"), оно выводит 25. Затем я обновил код, как показано ниже

$block_started++ if ( ($line =~ /^(status)/) && (index($line, "MaterializeU4") != 25)

Теперь это работает.

Любые комментарии приветствуются о моей практике.

Ответы [ 3 ]

6 голосов
/ 03 июня 2010

В Perl уже есть оператор для отслеживания блоков. Это называется оператором триггера:

Попробуйте это:

while ( <DATA> ) { 
   next if /\Q<U4 MaterializeU4()>\E/../^\s*$/;
   push @lines, $_;
}

Значение /\Q<U4 MaterializeU4()>\E/../^\s*$/ будет истинным , когда увидит строку, соответствующую начальному регулярному выражению, и перестанет быть истинным, когда увидит строку, соответствующую второму выражению.

1 голос
/ 03 июня 2010

Во-первых, лучше использовать регулярное выражение вместо индекса, так как вы можете настроить его на точный формат строки состояния, если решите быть строже, чем просто "подстрока существует"

Я бы предложил в качестве одного решения добавить второй флаг, чтобы пропустить содержимое блока, если это блок MaterializeU4, следующим образом:

# Read a constant definition block from a file handle. 
# void return when there is no data left in the file. 
# Empty return for skippable (Materialize4U) block!!!
# Otherwise return an array ref containing lines to in the block.  
sub read_block { 
    my $fh = shift; 
    my @lines = (); 
    my $block_started = 0; 
    my $block_ignore = 0;
    while (my $line = <$fh> ) { 
        if ($line =~ /^status.*?((MaterializeU4)?)/) {
            $block_started = 1;
            $block_ignore = 1 if $1;
        }
        last if $line =~ /^\s*$/ && $block_started;
        push @lines, $line unless $block_ignore; 
    } 
    return \@lines if @lines || $block_started;
    return; 
} 

Вот немного измененный пример, который я протестировал с помощью codepad.org:

Код:

use Data::Dumper;
my @all_lines = (
  "s 1" ,"b 1" ,""
, "s MaterializeU4" ,"b 2" ,""
, "s 3" ,"b 3" ,""
);

while (@all_lines) {
    my $block = read_block();
    print Data::Dumper->Dump([$block]);
}
exit 0;

sub read_block { 
    my @lines = (); 
    my $block_started = 0; 
    my $block_ignore = 0;
    while (my $line = shift @all_lines) { 
        if ($line =~ /^s .*?((MaterializeU4)?)/) {
            $block_started = 1;
            $block_ignore = 1 if $1;
        }
        last if $line =~ /^\s*$/ && $block_started;
        push @lines, $line unless $block_ignore; 
    } 
    return \@lines if @lines || $block_started;
    return; 
} 

выход

$VAR1 = [
          's 1',
          'b 1'
        ];
$VAR1 = [];
$VAR1 = [
          's 3',
          'b 3'
        ];
1 голос
/ 03 июня 2010

При успешном сопоставлении подстроки index возвращает позицию подстроки, которая может быть любым значением> = 0. При "сбое" index возвращает -1.

То, как вы используете index

index($line, "MaterializeU4") != 0

, будет истинно для всех строк, кроме строки, начинающейся со строки "MaterializeU4".

Похоже, вы уже немного знакомы с регулярными выражениями Perl.Почему бы не использовать его и в этом случае?

++$block_started if $line =~ /status/ && $line =~ /MaterializeU4/;

Другая проблема, которую я вижу, заключается в том, что вы устанавливаете $block_started, чтобы начать захват строк, но никогда не устанавливаете его в ноль в конце "блока"скажем, когда $line пусто.Я не уверен, что это то, что вы хотели сделать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...