Замена строки Perl не работает с $ 1 и $ 2 - PullRequest
0 голосов
/ 17 июня 2019

Поиск и замена не работают, когда я использую $ 1 и $ 2, определенные ранее.

Работает, когда я сохраняю его в новой переменной.

Не работает должным образом.

perl -e'
   my $name = "start middle end";
   my $rep = "";
   my $orig = "";
   if ($name =~ /sta(.*?)\s\w+\s(.*)/) {
      $orig = $1;
      $rep = $2;
      $name =~ s/$1/$2/;
      print "$name\n";
   }
'
sta middle end

Это потому, что $ 1 и $ 2 заменяются на новое $ name = ~ Я делаю?

Работает по назначению.

perl -e'
   my $name = "start middle end";
   my $rep = "";
   my $orig = "";
   if ($name =~ /sta(.*?)\s\w+\s(.*)/) {
      $orig = $1;
      $rep = $2;
      $name =~ s/$orig/${rep}/;
      print "$name\n";
   }
'
staend middle end

Есть ли лучший лайнер для этого?Я не хочу определять новые переменные.

Ответы [ 6 ]

4 голосов
/ 17 июня 2019

Да, новое успешное совпадение с регулярным выражением заменяет $1 и $2.

Вы можете полностью избежать глобальных переменных следующим образом:

perl -e'
   my $name = "start middle end";
   if ( my ($orig, $rep) = $name =~ /sta(.*?)\s\w+\s(.*)/ ) {
      $name =~ s/\Q$orig/$rep/;
      CORE::say $name;
   }
'

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

perl -e'
   my $name = "start middle end";
   if ( $name =~ s/sta\K.*?(?=\s\w+\s(.*))/$1/ ) {
      CORE::say $name;
   }
'

Однако я бы использовал следующее:

perl -e'
   my $name = "start middle end";
   if ( (my ($prefix, $suffix, $foo) = $name =~ /^(.*?sta).*?(\s\w+\s(.*))/ ) {
      CORE::say "$prefix$foo$suffix";
   }
'

Обратите внимание, что в вашем коде произошла ошибка вставка кода , котораяЯ исправил, используя quotemeta (как \Q).

2 голосов
/ 17 июня 2019

Переменные захвата сбрасываются путем выполнения совпадения в первой части оператора s ///, чтобы использовать замену.Оператор m // в контексте списка вернет захваченные значения, так что вы можете легко назначить их там.Также вы можете использовать \ Q ( quotemeta ), если строка поиска не является регулярным выражением.

perl -e'
   my $name = "start middle end";
   if (my ($orig, $rep) = $name =~ /sta(.*?)\s\w+\s(.*)/) {
      $name =~ s/\Q$orig/$rep/;
      print "$name\n";
   }
'
sta middle end
1 голос
/ 18 июня 2019

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

(sta)([a-z]*)\s+(\w+)\s+(.+)

Это просто еще один вариант.

TEST

perl -e'
    my $name = "start       middle    end";
    $name =~ s/(sta)([a-z]*)\s+(\w+)\s+(.+)/$1$4 $3 $4/;
    print "$name\n";
    '

OUTPUT

staend middle end

Пожалуйста, посмотрите демо здесь

0 голосов
/ 18 июня 2019

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

А пока, избегайте всего беспорядка и просто используйте одно регулярное выражение

 perl -e'
    my $name = "start middle end";
    $name =~ s/^(sta)(.*?)(\s\w+\s)(.*)/$1$4$3$4/;
    print "$name\n";
 '
0 голосов
/ 18 июня 2019

Вы можете избежать других переменных, используя глобальные массивы начала и конца последнего совпадения @- и @+ и просто заменяя подстроку:

my $name = "start middle end";
if ($name =~ /sta(.*?)\s\w+\s(.*)/) {
    substr($name, $-[1], $+[1]-$-[1], $2);
    print "$name\n";
}

См. Запись для @- в perldoc perlvar

0 голосов
/ 17 июня 2019

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

perl -lwe '$_ = "start middle end" ; if (/sta(.*?)\s\w+\s(.*)/) {my $rep = $2; s/$1/$rep/; print}'
staend middle end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...