2014-03-12 2 views
1

Я работаю над скриптом perl и нуждаюсь в некоторой помощи. Требование состоит в том, что я должен найти lable, и как только метка будет найдена, я должен заменить слово в строке сразу после метки. Например, если метка ABC:найти совпадение и заменить следующую строку в perl

ABC: 
string to be replaced 
some other lines 
ABC: 
string to be replaced 
some other lines 
ABC: 
string to be replaced 

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

Вот моя попытка:

open(my $fh, "<", "file1.txt") or die "cannot open file:$!"; 

while (my $line = <$fh>)) 
{ 
    next if ($line =~ /ABC/) { 

    $line =~ s/original_string/replaced_string/; 
    } 
    else { 
    $msg = "pattern not found \n "; 
    print "$msg"; 
    } 
} 

Правильно ли это ..? Любая помощь будет оценена.

+0

Сообщите нам, что вы ожидали и что видели. – gravitas

+0

Это домашнее задание? Если да, вернитесь назад и снова прочитайте свои заметки. – alexmac

+0

После того, как матч найден, он не может перейти к следующей строке. Похоже, что мое следующее утверждение неверно. Любые идеи, как включить это ...? – user3271367

ответ

0

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

#!/usr/bin/perl; 

use strict; 
use warnings; 

my $found; 
my $replacement = "Hello"; 
while(my $line = <>){ 
    if($line =~ /ABC/){ 
     $found = 1; 
     next; 
    } 
    if($found){ 
     $line =~ s/^.*?$/$replacement/; 
     $found = 0; 
     print $line, "\n"; 
    } 
} 
0

Или вы можете использовать File :: Slurp и читать весь файл в одну строку:

use File::Slurp; 
$x = read_file("file.txt"); 
$x =~ s/^(ABC:\s*$ [\n\r]{1,2}^.*?)to\sbe/$1to was/mgx;   
print $x; 

используя/м, чтобы сделать^и $ матч внедренный начать/конец строки
х чтобы позволить пробел после $ - есть, вероятно, лучший способ
Урожайность:

ABC: 
string to was replaced 
some other lines 
ABC: 
string to was replaced 
some other lines 
ABC: 
string to was replaced 
1

Вы делаете это в цикле :

next if ($line =~ /ABC/); 

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

Вот что вы сказали:

  • Я долженчитать файл, пока яне найтилинии сэтикеткой:
  • После того, как метка найдена
  • У меня естьчитайте следующую строку изамените слово в строке, следующей за меткой.

Итак:

  • Вы хотите прочитать файл строку за строкой.
    • Если линия совпадает с маркировкой
      • прочитать следующую строку
      • заменить текст на линии
    • Распечатайте линию

По этим направлениям:

use strict; 
use warnings;     # Hope you're using strict and warnings 
use autodie;     # Program automatically dies on failed opens. No need to check 
use feature qw(say);   # Allows you to use say instead of print 


open my $fh, "<", "file1.txt"; # Removed parentheses. It's the latest style 

while (my $line = <$fh>) { 
    chomp $line;    # Always do a chomp after a read. 
    if ($line eq "ABC:") { # Use 'eq' to ensure an exact match for your label 
     say "$line";   # Print out the current line 
     $line = <$fh>   # Read the next line 
     $line =~ s/old/new/; # Replace that word 
    } 
    say "$line";    # Print the line 
} 
close $fh;      # Might as well do it right 

Обратите внимание, что когда я использую say, мне не нужно ставить \n в конце строки. Кроме того, выполнив мой chomp после моего чтения, я легко смогу сопоставить ярлык, не беспокоясь о \n на конце.

Это делается именно так, как вы сказали, это должно быть сделано, но есть пара вопросов. Во-первых, когда мы делаем $line = <$fh>, нет никакой гарантии, что мы действительно читаем строку. Что делать, если файл заканчивается прямо там?

Кроме того, это плохая практика для чтения файла в нескольких местах. Это затрудняет сохранение программы. Чтобы обойти эту проблему, мы будем использовать переменную . Это позволяет нам знать, если линия, прежде чем был ярлыком или нет:

use strict; 
use warnings;     # Hope you're using strict and warnings 
use autodie;     # Program automatically dies on failed opens. No need to check 
use feature qw(say);   # Allows you to use say instead of print 

open my $fh, "<", "file1.txt"; # Removed parentheses. It's the latest style 

my $tag_found = 0;    # Flag isn't set 
while (my $line = <$fh>) { 
    chomp $line;    # Always do a chomp after a read. 
    if ($line eq "ABC:") { # Use 'eq' to ensure an exact match for your label 
     $tag_found = 1   # We found the tag! 
    } 
    if ($tag_found) { 
     $line =~ s/old/new/; # Replace that word 
     $tag_found = 0;  # Reset our flag variable 
    } 
    say "$line";    # Print the line 
} 
close $fh;      # Might as well do it right 

Конечно, я бы предпочел, чтобы устранить загадочные значения. Например, тег должен быть переменной или константой. То же самое со строкой, которую вы ищете, и с строкой, которую вы заменяете.

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

$line =~ s/\b$old_word\b/$new_word/; 

The \b знак границы слова. Таким образом, если вы предположите, заменить слово кот с собакой, вы не получите споткнулись на линии, которая говорит:

The Jeopardy category is "Say what". 

Вы не хочешь, чтобы изменить category к dogegory ,

0

Кроме того, опираясь на в Perl in-place editing:

use File::Slurp qw(read_file write_file); 

use strict; 
use warnings; 

my $file = 'fakefile1.txt'; 

# Initialize Fake data 
write_file($file, <DATA>); 

# Enclosed is the actual code that you're looking for. 
# Everything else is just for testing: 
{ 
    local @ARGV = $file; 
    local $^I = '.bac'; 

    while (<>) { 
     print; 
     if (/ABC/ && !eof) { 
      $_ = <>; 
      s/.*/replaced string/; 
      print; 
     } 
    } 

    unlink "$file$^I"; 
} 

# Compare new file. 
print read_file($file); 

1; 

__DATA__ 
ABC: 
string to be replaced 
some other lines 
ABC: 
string to be replaced 
some other lines 
ABC: 
string to be replaced 
ABC: 

выходы

ABC: 
replaced string 
some other lines 
ABC: 
replaced string 
some other lines 
ABC: 
replaced string 
ABC: 
0

Следующая один лайнер будет делать то, что вам нужно:

perl -pe '++$x and next if /ABC:/; $x-- and s/old/new/ if $x' inFile > outFile 

Код устанавливает флаг и получает следующую строку, если метка найдена. Если флаг установлен, он не устанавливается и выполняется замещение.

Надеюсь, это поможет!

Смежные вопросы