Что в Perl означает if (s/^\+//)?

В коде Perl/Tk я нашел условное выражение, как показано ниже.

if (s/^\+//)
{
   #do something
}
elsif (/^-/)
{
   #do another thing
}

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


person Kadiam    schedule 22.11.2012    source источник
comment
@Oded, эта ссылка не самый плохой учебник по Perl, который я когда-либо видел, но он довольно старый и использует несколько устаревших методов (-w против warnings, прототипы). Я мог бы порекомендовать perldoc perlretut.   -  person Joel Berger    schedule 22.11.2012
comment
@JoelBerger - Достаточно честно. Это был первый хит от Google.   -  person Oded    schedule 22.11.2012
comment
@ Одед, НП. Сообщество пытается бороться с долговечностью учебных пособий по Perl, создавая/выделяя более новые и лучшие, и предупреждая о старых/плохих perl-tutorial.org. Perl получил дурную славу после того, как бум доткомов принес много плохого кода, и мы пытаемся сделать его лучше, шаг за шагом.   -  person Joel Berger    schedule 22.11.2012
comment
Я добавил это руководство в список устаревших руководств на perl-tutorial.org. Он тратит слишком много времени на какой-то старый синтаксис, но делает приличную работу, касаясь нового. Это не плохо, но не лучший вариант для новичка.   -  person Joel Berger    schedule 22.11.2012
comment
Что вы сделали, чтобы попытаться понять этот код? Документация, поставляемая с Perl, действительно исчерпывающая. Что помешало вам найти там ответы?   -  person Dave Cross    schedule 23.11.2012


Ответы (4)


Они оба являются регулярными выражениями. Вы можете прочитать о них на страницах perlre и perlretut. Вы можете поиграть с ними на http://www.rubular.com/r/CEtqZ3YUIi.

Они оба неявно что-то делают с $_. Вероятно, вокруг ваших строк кода без переменной цикла есть while или foreach. В этом случае $_ становится этой переменной цикла. Например, он может содержать текущую строку файла, который читается.

  1. Если текущее значение $_ содержит знак + (плюс) в качестве первого символа в начале строки, #do somehting.
  2. В противном случае, если он содержит знак - (минус), #do another thing.

В случае 1. он также заменяет этот знак + ничем (т.е. удаляет его). Однако он не удаляет - в 2..


Давайте посмотрим на объяснение с помощью YAPE::Regex::Explain.

use YAPE::Regex::Explain;
print YAPE::Regex::Explain->new(qr/^\+/)->explain();

Вот. Не очень полезный в нашем случае, но, тем не менее, хороший инструмент. Обратите внимание, что части (?-imsx и ) — это то, что подразумевает Perl по умолчанию. Они всегда там, если вы не измените их.

The regular expression:

(?-imsx:^\+)

matches as follows:

NODE                     EXPLANATION
----------------------------------------------------------------------
(?-imsx:                 group, but do not capture (case-sensitive)
                         (with ^ and $ matching normally) (with . not
                         matching \n) (matching whitespace and #
                         normally):
----------------------------------------------------------------------
  ^                        the beginning of the string
----------------------------------------------------------------------
  \+                       '+'
----------------------------------------------------------------------
)                        end of grouping
----------------------------------------------------------------------

Обновление: как отметил Микко Л. в комментариях, вам, возможно, следует реорганизовать/изменить этот фрагмент кода. Хотя он, вероятно, делает то, что должен, я считаю, что было бы неплохо сделать его более читабельным. Тот, кто написал это, очевидно, не заботился о вас как о более позднем сопровождающем. Я предлагаю вам это сделать. Вы можете изменить его на:

# look at the content of $_ (current line?)
if ( s/^\+// )
{
  # the line starts with a + sign,
  # which we remove!

  #do something
}
elsif ( m/^-/ )
{
  # the line starts witha - sign
  # we do NOT remove the - sign!

   #do another thing
}
person simbabque    schedule 22.11.2012
comment
Ваш анализ точен. Я бы добавил, что ОП должен рассмотреть возможность рефакторинга этого фрагмента кода, чтобы замена была более очевидной. Это очень легко пропустить, как это написано сейчас. Даже просто посещение if( /^\+/ ) { $_ =~ s/^\+//; # do something } значительно помогло бы. - person Mikko L; 22.11.2012
comment
@MikkoL Я согласен и добавил предложения. Я не согласен с явным использованием $_, но я считаю, что это личное предпочтение. Спасибо. - person simbabque; 22.11.2012
comment
Downvoter, не могли бы вы прокомментировать, как я могу улучшить свой пост? - person simbabque; 22.11.2012
comment
Я не такой большой поклонник этого рефакторинга. Он добавляет еще одно сопоставление с образцом, а сопоставление с образцом в некоторых случаях может быть довольно дорогим. Кроме того, использование if (s/.../.../) для проверки того, имела ли место замена, является довольно обычной идиомой Perl. Если вы беспокоитесь о ясности, комментарий подойдет (Примечание: я не против - ответ в целом хороший). - person dan1111; 22.11.2012
comment
Я согласен с Дэном, нет причин не s/// одновременно сопоставлять и удалять маркер. Вот почему шаблоны возвращают количество совпадений/замен в скалярном контексте. - person Joel Berger; 22.11.2012
comment
В целом я тоже согласен. Тем не менее, я думаю, что комментарий Mikko L был хорошим. Я решил пойти с ним, потому что OP, очевидно, не очень силен в Perl, поэтому я подумал, что полезность явного варианта с дополнительным совпадением перевешивает стоимость этого другого совпадения. Я изменю это. - person simbabque; 22.11.2012

Это регулярные выражения, используемые для сопоставления с образцом и замены.

Вы должны прочитать концепцию, но что касается вашего вопроса:

s/^\+//

Если строка начинается с плюса, удалите этот плюс ("s" означает "заменить") и верните true.

/^-/

Истинно, если строка начинается с минуса.

person Thilo    schedule 22.11.2012

Этот код эквивалентен

if ($_ =~ s/^\+//) {  # s/// modifies $_ by default
   #do something
}
elsif ($_ =~ m/^-/) {  # m// searches $_ by default
   #do another thing
}

s/// и m// являются операторами, подобными кавычкам регулярных выражений. Вы можете прочитать о них в perlop.

person Eugene Yarmash    schedule 22.11.2012
comment
Это совершенно хороший (хотя и короткий) ответ. Я не понимаю, почему за это проголосовали. - person simbabque; 22.11.2012
comment
Я не понизил голос, но я уверен, что это потому, что здесь речь идет не о неявной переменной, а о самом шаблоне подстановки. - person Joel Berger; 22.11.2012

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

#!/usr/bin/env perl

use strict;
use warnings;

my $args = {};

for ( @ARGV ) {
  if ( s/^no// ) {
    $args->{$_} = 0;
  } else {
    $args->{$_} = 1;
  }
}

use Data::Dumper;
print Dumper $args;

Когда вы вызываете скрипт, например

./test.pl hi nobye

Вы получаете

$VAR1 = {
          'hi' => 1,
          'bye' => 0
        };

Ключ представляет собой строку, однако, если ему предшествует no, удалите его (чтобы получить рассматриваемый ключ) и вместо этого установите значение 0.

Пример OP немного сложнее, но следует той же логике.

  • если ключ начинается с +, удалите его и сделайте что-нибудь
  • если ключ начинается с -, не удаляйте его и сделайте что-нибудь еще
person Joel Berger    schedule 22.11.2012