perlでの以下のステートメントの意味は何ですか?
($script = $0) =~ s#^.*/##g;
演算子 =~ と右側のステートメント s#^.*/##g を理解しようとしています。
ありがとう
perlでの以下のステートメントの意味は何ですか?
($script = $0) =~ s#^.*/##g;
演算子 =~ と右側のステートメント s#^.*/##g を理解しようとしています。
ありがとう
=~
右側のもの (パターン マッチまたは検索と置換) を左側のものに適用します。そこについてはたくさんのドキュメント=~
があるので、かなり良いものを紹介します。
そこにはいくつかのイディオムがあり、それらは明らかでも十分に文書化されていないため、つまずく可能性があります。それらをカバーしましょう。
まずはこれ…
($copy = $original) =~ s/foo/bar/;
これは、変数をコピーし、検索と置換を 1 ステップで実行する方法です。これは以下と同等です:
$copy = $original;
$copy =~ s/foo/bar/;
は、左側のコードが実行された 後=~
、左側にあるものに作用します。コピーに対する行為はそう評価されます。($copy = $original)
$copy
=~
s#^.*/##g
と同じですが、代替の区切り文字s/^.*\///g
を使用して、つまようじの傾き症候群を回避します。正規表現の区切り文字として、ほぼ何でも使用できます。 は一般的ですが、見苦しく読みにくいと思います。バランスが取れているので、 私は好きです。同等のコードです。#
{}
s{^.*/}{}g
イディオムを展開すると、次のようになります。
$script = $0;
$script =~ s{^.*/}{}g;
$0
スクリプトの名前です。したがって、これはスクリプトの名前をコピーし、最後のスラッシュまですべてを削除するコードです (.*
貪欲で、可能な限り一致します)。スクリプトのファイル名だけを取得しています。
は/g
、文字列に対して可能な限り多くの一致を実行することを示します。これは 1 回しか一致^
しないため (文字列の先頭に固定されます)、何の役にも立ちません。
これを行うには、より適切で安全な方法があります。
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 =~ s@old@new@;
これらの 4 つの式はすべて同じものです。old
文字列をnew
my に置き換えます$string
。の後に来るものはs
すべてセパレーターです。括弧、中括弧、および角括弧はペアリングを使用することに注意してください。これは、単一引用符と二重引用符の代わりに使用できるq
andに対してかなりうまく機能します。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
。s
文字は、検索と置換の正規表現を示します。#
区切り文字として使用されています。通常、正規表現パターンの引用文字は文字ですが、この場合/
を含め、他の文字を使用することもできます。#
^.*/
. .
これは、「文字列の先頭で、スラッシュまで 0 個以上の文字を検索することを意味します。これにより、改行文字 (デフォルトでは一致しません)を除いて、各行でキャプチャが続けられます。」#
「置換」値の開始を示す。通常、最初の行のキャプチャされた部分を使用するパターンがここにあります。#
もう一度。これで置換パターンは終了です。置換パターンの開始と終了の間に何もなかったので、最初に見つかったものはすべて何も置き換えられません。g
、またはグローバル マッチ。検索と置換は、値が一致する回数だけ発生し続けます。事実上、 value 内の / の前のすべての値を検索して空にしますが、スクリプトの名前ではすべての改行を保持します。Unix のようなパスでのみ機能する長いスクリプトで呼び出されたときに、スクリプト名を取得するのは非常に怠惰な方法です。
機会があればFile::Basename
、Perl のコア モジュールである に置き換えることを検討してください。
use File::Basename;
# later ...
my $script = fileparse($0);