Заменить несколько экземпляров в строке в Perl - PullRequest
0 голосов
/ 25 июня 2009

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

Line1 : AA BB CC DD EE

Я хочу заменить это на

1 2 3 4 5

выход

Line1: 1 2 3 4 5

В одном регулярном выражении на Perl я могу сделать это

Я пытался это, но безуспешно

my @arr1 = ("AA", "BB", "CC", "DD", "EE");
open F2, $file;
my $count = 0;
while (<F2>) {
    my $str = $_;
    $str =~ s/$arr[$count]/$count+1/g;
    print to file
}

close(F2);

Это не дает никаких идей

Ответы [ 5 ]

2 голосов
/ 25 июня 2009

Вам нужно что-то сделать, чтобы изменить файл на месте, чего вы в данный момент не делаете. Самый простой вариант - использовать File :: Inplace (или для вывода во второй файл).

Кроме того, вы не зацикливаетесь на массиве, а на строках файла, поэтому он заменит только $ arr [0] на 1 в каждой строке.

  use strict;
  use warnings;
  use File::Inplace;

  my @replacees = ("AA", "BB", "CC", "DD", "EE");
  my $editor = new File::Inplace(file => "file.txt", regex => "\n");
  while (my ($line) = $editor->next_line) {
    my $count = 1
    for my $replacee (@replacees) { 
        if ($line =~ m/$replacee/) {
            $line =~ s/$replacee/$count/g;
        }
        $count = $count + 1;
    }
    $editor->replace_line($line);
  }
  $editor->commit;
2 голосов
/ 25 июня 2009

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

my @arr1 = ("AA", "BB", "CC", "DD", "EE");
my %replacements = map { ($arr1[$_] => $_ + 1) } (0..$#arr1);
my $regexp = join( '|', sort { length($b) <=> length($a) } @arr1);

open F2, $file;
while (<F2>) {
    my $str = $_;
    $str =~ s/($regexp)/$replacements{$1}/ge;
    print $str;
}
close(F2);

Важные части:

my %replacements = map { ($arr1[$_] => $_ + 1) } (0..$#arr1);

Он создает хеш с ключами от @ arr1, а значения - это индекс заданного значения в @ arr1, увеличенный на 1.

Например, для @ arr1 = ("a", "b", "d", "c"); % замен будет: ("a" => 1, "b", => 2, "c" => 4, "d" => 3);

my $regexp = join( '|', sort { length($b) <=> length($a) } @arr1);

Это строит базовое регулярное выражение для поиска всех слов из @ arr1. Часть сортировки упорядочивает слова по убыванию. Таким образом, для @ arr1 = ("a", "ba", "bac") $ regexp будет равно "bac | ba | a".

Этот порядок важен, так как в противном случае могут возникнуть проблемы, если какое-либо из слов будет префиксом любого другого слова (как, например, с "ba" и "bac" в моем примере).

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

open my $fh, 'filename';

или еще лучше:

open my $fh, '<', 'filename';
2 голосов
/ 25 июня 2009

Если я правильно понимаю, вы хотите заменить каждое слово числом (увеличивается на 1 после каждого слова). Вот программа с тестами:

#!/usr/bin/perl

use strict;
use warnings;
use Test::More qw(no_plan);

sub replace {
  my $str=shift;
  my $count=1;
  $str=~s/\w+/$count++/ge;
  return $str;
}


is(replace('AA AA DD EE'),'1 2 3 4');
is(replace('A B C D E'),'1 2 3 4 5');
0 голосов
/ 02 марта 2011

В любом случае это будет работать

my% arr2 = ('AA' => 1, 'BB' => 2, 'CC' => 3, 'DD' => 4, 'EE' => 5, 'FF' => 6) ;

открыть F2, "t1.txt";
открыть F3, "> out.txt";
while () {
my $ str = $ ;
распечатать F3 join '', map {s / $
/ $ arr2 {$ } / g; $ } split / /, $ str;
печать F3 "\ n";
}

близко (F2); * 1 018 * закрыть (F3);

или

my @ arr1 = ("AA", "BB", "CC", "DD", "EE", "FF");
my% hashArr = map {($ arr1 [$ ] => $ + 1)} (0 .. $ # arr1);

открыть F2, "t1.txt";
откройте F3, "> out.txt";
while () {
my $ str = $ ;
распечатать F3 join '', map {s / $
/ $ hashArr {$ } / g; $ } split / /, $ str;
печать F3 "\ n";
}

* * Тысяча сорок-одиной близко (F2);
закрыть (F3); * * тысяча сорок-три
0 голосов
/ 25 июня 2009

Сначала коррекция:

while (<F2>) {
    my $str = $_;

Если вы хотите, чтобы прочитанная строка заканчивалась на $str, нет никаких причин для участия $_ в процессе:

while (my $ str =) {

, который также поднимает мысль, высказанную depesz , что вы должны использовать лексические файловые дескрипторы, а не упаковывать глобальные дескрипторы файлов без слов.

Теперь, глядя на вашу петлю:

my $count = 0;
while (my $str = <$input_fh>) {
    $str =~ s/$arr[$count]/$count+1/g;
    # ...
}

представляется неявным предположение, что в файле не может быть больше строк, чем количество элементов в @foo. В этом случае вам не нужно использовать $count: $. отлично подойдет. Скажи, что ты на второй линии. Ваш код говорит, что вы хотите заменить все вхождения BB в этой строке на 2, что отличается от того, что вы описываете в устной форме.

Это важный момент: Любой код, который вы публикуете, должен соответствовать словесному описанию .

В любом случае, вот один из способов:

rty.pl

#!/usr/bin/perl

use strict;
use warnings;

use File::Slurp;

my ($input) = @ARGV;

write_file(
    $input, [
        map { s/( ([A-Z]) \2 )/ord($2) - ord('A') + 1/gex; $_ } read_file $input
    ]
);
__END__

test.data:

Line1 : AA BB CC DD EE
Line1 : AA BB CC DD EE
Line1 : AA BB CC DD EE
Line1 : AA BB CC DD EE

$ rty.pl test.data

test.data после вызова скрипта:

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