10

perl中以下语句的含义是什么?

($script = $0) =~ s#^.*/##g;

我试图理解运算符 =~ 以及右侧 s#^.*/##g 的语句。

谢谢

4

3 回答 3

28

=~将右侧的事物(模式匹配或搜索和替换)应用于左侧的事物。有很多关于=~那里的文档,所以我只想为您指出一个非常好的文档。

那里有几个成语不明显,也没有很好的记录,可能会让你绊倒。让我们覆盖它们。

首先是这个...

($copy = $original) =~ s/foo/bar/;

这是一种复制变量并在一个步骤中对其执行搜索和替换的方法。它相当于:

$copy = $original;
$copy =~ s/foo/bar/;

运行左侧代码后,对左侧的=~任何内容进行操作。 评估为对副本执行的操作。($copy = $original)$copy=~

s#^.*/##gs/^.*\///g使用替代定界符以避免倾斜牙签综合症相同。您几乎可以使用任何东西作为正则表达式分隔符。 #很常见,尽管我认为它丑陋且难以阅读。我更喜欢{},因为他们平衡。 s{^.*/}{}g是等效代码。

展开成语,你有这个:

$script = $0;
$script =~ s{^.*/}{}g;

$0是脚本的名称。所以这是复制脚本名称并将所有内容剥离到最后一个斜杠(.*贪婪并且会尽可能匹配)的代码。它只获取脚本的文件名。

/g表示对字符串执行尽可能多的匹配。由于这只能匹配一次(将其^锚定到字符串的开头)它没有任何用途。

有一种更好、更安全的方法可以做到这一点。

use File::Basename;
$script = basename($0);
于 2013-01-15T00:54:17.567 回答
5

这非常非常简单:

Perl类似引号的表达式可以采用许多不同的字符作为部分分隔符。命令之后的分隔符(在本例中为s)是其余操作的分隔符。例如:

 # Out with the "Old" and "In" with the new

 $string =~ s/old/new/;
 $string =~ s#old#new#;
 $string =~ s(old)(new);
 $string =~ s@old@new@;

所有这四种表达方式都是一样的。他们用oldnew$string. 之后的任何s内容都是分隔符。请注意,括号、花括号和方括号使用配对。这对于qand qqwhich 可以用来代替单引号和双引号非常有效:

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 的老手来说也是如此。

于 2013-01-15T02:02:55.567 回答
4

在 perl 中,您可以使用多种字符作为引用字符(字符串、正则表达式、列表)。让我们分解一下:

  • $script为变量分配内容$0(包含调用脚本名称的字符串。)
  • =~字符是绑定运算符。 它调用正则表达式匹配或正则表达式搜索和替换。在这种情况下,它与新变量 匹配$script
  • s字符表示搜索和替换正则表达式。
  • #字符被用作正则表达式的分隔符。正则表达式模式引号字符通常是/字符,但您可以使用其他字符,包括#在这种情况下。
  • 正则表达式,^.*/。这意味着,“在字符串的开头,搜索零个或多个字符,直到出现斜杠。这将继续捕获每一行,但换行符除外(.默认情况下不匹配。)
  • 指示“替换”值的#开始。通常,您在这里有一个模式,它使用第一行的任何捕获部分。
  • #再次。这结束了替换模式。由于替换模式的开始和结束之间没有任何内容,因此在第一个中找到的所有内容都将被替换为任何内容。
  • g,或全局匹配。搜索和替换将继续发生与值匹配的次数。

实际上,搜索并清空 value 中 / 之前的每个值,但保留脚本名称中的所有换行符。当在仅适用于类 unix 路径的长脚本中调用时,这是获取脚本名称的一种非常懒惰的方式。

如果有机会,请考虑用File::BasenamePerl 中的核心模块替换:

use File::Basename;

# later ... 

my $script = fileparse($0);
于 2013-01-15T00:52:27.240 回答