В чем смысл выражения ниже в perl?
($script = $0) =~ s#^.*/##g;
Я пытаюсь понять оператор = ~ вместе с утверждением в правой части s # ^. */## g.
Спасибо
В чем смысл выражения ниже в perl?
($script = $0) =~ s#^.*/##g;
Я пытаюсь понять оператор = ~ вместе с утверждением в правой части s # ^. */## g.
Спасибо
=~
применяет вещь справа (совпадение с образцом или поиск и замена) на предмет слева. Там есть много документации о =~
, поэтому я просто собираюсь указать вам довольно хороший.
Там есть пара идиом, которые не очевидны и не задокументированы, что может сбить вас с толку. Пусть они будут покрыты.
Сначала это...
($copy = $original) =~ s/foo/bar/;
Это способ копирования переменной и выполнения поиска и замены на нем за один шаг. Это эквивалентно:
$copy = $original;
$copy =~ s/foo/bar/;
=~
работает на том, что находится слева после того, как был запущен код левой руки. ($copy = $original)
оценивается как $copy
, поэтому =~
действует на копию.
s#^.*/##g
- это то же самое, что и s/^.*\///g
, но используя альтернативные разделители, чтобы избежать Синтаксический синдром откидывания, Вы можете использовать что угодно как разделитель регулярных выражений. #
распространен, хотя я считаю его уродливым и трудным для чтения. Я предпочитаю {}
, потому что они балансируют. s{^.*/}{}g
является эквивалентным кодом.
Развертывание идиом, у вас есть это:
$script = $0;
$script =~ s{^.*/}{}g;
$0
- это имя script. Таким образом, это код для копирования имени script и разбивки всех до последней косой черты (.*
является жадным и будет соответствовать как можно больше). Он получает только имя файла script.
/g
указывает на выполнение совпадения в строке столько раз, сколько возможно. Так как это может только когда-либо совпадать один раз (^
привязывает его к началу строки), это нецелесообразно.
Там лучший и безопасный способ сделать это.
use File::Basename;
$script = basename($0);
Это очень, очень просто:
Котировочные выражения Perl могут принимать множество разных символов в качестве разделителей разделов. Сепаратор сразу после команды (в этом случае s
) является разделителем для остальной части операции. Например:
# Out with the "Old" and "In" with the new
$string =~ s/old/new/;
$string =~ s#old#new#;
$string =~ s(old)(new);
$string =~ [email protected]@[email protected];
Все четыре из этих выражений - одно и то же. Они заменяют строку old
на new
в моей $string
. Все, что приходит после s
, является разделителем. Обратите внимание, что в скобках, фигурных скобках и квадратных скобках используются корректировки. Это хорошо работает для q
и qq
, которые можно использовать вместо одиночных кавычек и двойных кавычек:
print "The value of \$foo is \"foo\"\n"; # A bit hard to read
print qq/The value of \$foo is "$foo"\n/; # Maybe slashes weren't a great choice...
print qq(The value of \$foo is "$foo"\n); # Very nice and clean!
print qq(The value of \$foo is (believe it or not) "$foo"\n); #Still works!
Последнее по-прежнему работает, потому что котировки типа операторов подсчитывают открывающие и закрывающие круглые скобки. Конечно, с регулярными выражениями скобки и квадратные скобки являются частью синтаксиса регулярных выражений, поэтому вы не увидите их так много в подстановках.
В большинстве случаев настоятельно рекомендуется придерживаться формы s/.../.../
только для удобства чтения. Это то, к чему люди привыкли, и легко усваивается. Однако, что, если у вас есть это?
$bin_dir =~ s/\/home\/([^\/]+)\/bin/\/Users\/$1\bin/;
Эти обратные косые черты могут затруднить чтение, поэтому традиция заключалась в замене разделителей обратной косой черты, чтобы избежать эффекта холмов и долин.
$bin_dir =~ s#/home/([^/]+)/bin#/Users/$1/bin#;
Это немного сложно прочитать, но, по крайней мере, мне не нужно процитировать каждую косую черту и обратную косую черту, поэтому мне легче увидеть, что я заменяю. Регулярные выражения сложны, потому что хороших персонажей цитат трудно найти. Различные специальные символы, такие как ^
, *
, |
и +
являются магическими символами регулярного выражения и, вероятно, могут быть в регулярном выражении, используется #
. Это не часто встречается в строках, и в регулярном выражении оно не имеет особого значения, поэтому оно не будет использоваться.
Возвращаясь к исходному вопросу:
($script = $0) =~ s#^.*/##g;
является эквивалентом:
($script = $0) =~ s/^.*\///g;
Но поскольку исходный программист не хотел возвращать эту косую черту, они изменили символ разделителя.
Что касается:
($ script= $0) = ~ s # ^. */## g; `
Это то же самое, что сказать:
$script = $0;
$script =~ s#^.*/##g;
Вы назначаете переменную $script
и выполняете замену за один шаг. Это очень распространено в Perl, но сначала это трудно понять.
Кстати, если я понимаю это основное выражение (Удаление всех символов до последней косой черты. Это было бы более чистым:
use File::Basename;
...
$script = basename($0);
Намного легче читать и понимать - даже для старой руки Perl.
В perl вы можете использовать много видов символов в качестве символов цитирования (строка, регулярное выражение, список). давайте сломаем его:
$script
содержимое $0
(строка, содержащая имя вызывающего script.)=~
- это оператор привязки . Он вызывает регулярное выражение или поиск и замену регулярных выражений. В этом случае он соответствует новой переменной $script
.s
указывает на поиск и замену регулярного выражения.#
используется как разделитель для регулярного выражения. Характер кавычки шаблона регулярного выражения обычно является символом /
, но вы можете использовать другие, в том числе #
в этом случае.^.*/
. Это означает, что "в начале строки поиск нулевого или большего количества символов до косой черты. Это будет удерживать захват в каждой строке, кроме символов новой строки (который .
не соответствует по умолчанию.)#
, указывающий начало значения "replace". Обычно у вас есть шаблон, который использует любую захваченную часть первой строки.#
снова. Это завершает шаблон замены. Поскольку между началом и концом шаблона замены не было ничего, все, что было найдено в первом, заменено ничем.g
или глобальное соответствие. Поиск и замена будут продолжаться столько раз, сколько он соответствует значению.Эффективно ищет и опустошает каждое значение перед значением /, но сохраняет все новые строки в имени script. Это действительно ленивый способ получить имя script при вызове в длинном script, который работает только с unix-подобным путем.
Если у вас есть шанс, подумайте о замене с помощью File::Basename
, основного модуля в Perl:
use File::Basename;
# later ...
my $script = fileparse($0);