「パスワード暗号化について(CGIスクリプト)」の続きとなっています。文字数が800文字を超えてしまったため、分割させていただきました。
続いて解読処理です。こっちは更に謎です。
$salt = $logpassword =~ /^\$1\$(.*)\$/ && $1 || substr($logpassword, 0, 2);
最初は//内の処理です。$1$だけは読めますが、「^」も「(.*)」も最後の$も不明です。「^」はEXORではありませんよね・・・?
次に&&とやはり||です。この辺は「え?ギャグ?」って感じです(まったく分かってません)。
最後にパターン結合演算子ですが・・・。「スカラー式をm//、s///、tr///と結びつける」と言われても何のことやら。大体上の表記ではmもsもtrも使ってないんで・・・。マッチmの略形でしょうか?
ということで長くなってしまいましたが、これらの動作の目的、そして動作原理を教えていただきたく質問させていただきました。
どうかよろしくお願いします。
No.1
- 回答日時:
おっしゃるとおり//はm//の省略形です。
ですから「^」は、正規表現の「文字列先頭」をあらわす記号です。よってこの部分は
「$logpasswordが '$1$' で始まり0以上の何文字かが続き$が来るような文字
列か?」
といったことを調査しています。
&&や||は、論理演算子ですね。A && Bで
「Aを評価(実行するってことです)して、真なら続けてBを評価してその結果を
返す。Aが偽ならBには一切感知せず偽を返す」
ということになり、A || Bで
「Aを評価して、真ならBには一切感知せずその結果を返す。Aが偽なら引き続
きBを評価してその結果を返す。」
ということになります。
上記の意味は総じて以下のようなことなんじゃないでしょうか。
「$logpasswordがこれこれのような文字列で、しかも途中の(.*)部分が
真(つまり空文字列じゃない)だったときはその(.*)部分を、
そうじゃないときは$logpasswordの先頭から2文字を取り出して、
saltに入れてください」
if文で書きなおすと上記の式は以下のようなことに
なると思います。
if ($logpassword =~ m/^\$1\$(.*)\$/) {
if (defined($1) && $1 ne '') {
$salt = $1;
} else {
$salt = substr($logpassword, 0, 2);
}
} else {
$salt = substr($logpassword, 0, 2);
}
まあたしかに初めてご覧になった方にはわかりやすいものではないでしょうが
…あんまりPerlをいじめないであげてください。&&や||をこのように使うのは
Cでもshellでもいろんな言語にもありまして、UNIX関係者には馴染みがある用法です。
lispなどではむしろifよりもこちらのほうが標準的です。
馴れると最初のような式の方が上記ifを使ったものより読みやすくなったりし
ます。
もちろん、「おれはifで書いた方がいいぜ!」とお思いになるのでしたら
誰にかまうことなくそうお書きになればよろしいでしょう。
どう書いてもいいのがPerlです。
この回答への補足
早速のご回答ありがとう御座います。とてもわかりやすい説明で助かりました。でももうちょっと分からないところがあるので、迷惑ついでにお願いいたします。
さて、まず残った疑問点なんですが、やはり、
「$logpassword =~ m/^\$1\$(.*)\$/」
の式ですね。
ひとまずm//がマッチ演算子だということが理解できました。そして「^」ですが、これは要するに文字列の先頭から評価していくんだ、ということで、いいんですかね?初心者の目で見ると、変数の中身の評価なんていつでも最初から始まるじゃないかと思うんですが・・・。これはそういうことではなく、「n文字目から評価する場合もあるので、それじゃないということを明示している」ということなのでしょうか?
1,次に(.*)ですが、これは「パターンの中の()で囲んだ部分」ですよね。「.*」は要するに「任意の1文字の0回以上の繰り返し(0回以上ってことは、全く何もない時でも一応評価する、ということでしょうか、それとも0は真でも空文字は偽、を示すのでしょうか)」を示していて、結局は「マッチ成功時に、最初の1文字($1)を引っこ抜いて$saltに代入する」と読んで正解なのでしょうか?
・・・なんか何言ってるのか分からないですね(汗)。
2,そういうことじゃなく、「$_の最初が$1$で始まって途中がどーでもよくて、最後に$が来るっていう文字列だった場合にはその途中の部分を抜き出して$1に代入するんだ」ってことなんですかね。
・・・意見が上の2つに分かれています。僕の中で(汗)。
できれば2番が正解であって欲しいんですが・・・(1番は謎に包まれています)。
2番が正解なら、「if (defined($1) && $1 ne '') 」の部分も「$1がひとまずなんらかの文字なら」の一言で決着が付くんですよね。
という感じで考察してみました。いかがなものでしょうか?
ちなみに、個人的にPerlは好きです。Cをちょっとかじっていたので、Perlの謎の破壊力にちょっと驚いているところです(@log = <IN>;とかforeach(0 .. $#data){}とか)。
今回、「if($data){}ってなんなんだ!?」ってことを理解した(真と偽について初めて知った)ときのような感じを論理演算子でまた味わいました。慣れるとついつい使ってしまうような表現ですね。面白いです。
というわけで、また何かしら多分きっとお世話になると思うので今後ともよろしくお願いします。
No.2ベストアンサー
- 回答日時:
こちらこそよろしくお願いします。
正規表現に付いては、それこそ一冊の本にもなっているくらいなので、あとで
じっくりラクダ本やその「詳説 正規表現」(http://www.oreilly.co.jp/BOOK/regex/)
をご覧いただくといいと思いますが、とりあえず簡単に補足しておきます。
まず「^」ですが、これは「頭から評価していく」という意味ではありません。
「n文字目から…」の方が正解です。
$a = 'Perl is not a Pearl';
$b = 'What is Perl?';
のとき、
$a = /^Perl/; は先頭がPerlで始まるので真
$b = /^Perl/; は先頭がWhatで始まるので偽
$a = /Perl/; はPerlを含むので真
$b = /Perl/; もPerlを含むので真
となります。
「.*」は0回でも一致します。/Pe.*rl/ はPerlにもPearlにもマッチします。
1回以上必ずなにかないといけない場合は/Pe.+rl/と「+」を使います。
上の例で言うとこの正規表現は$aでは真、$bでは偽になります。
さて、「()」は実際のカッコを指しているのではないことにご注意ください。
'This is (not) Perl' =~ /(.*)/ も真ですし、'This is not Perl' =~ /(.*)/
も真です。本来の「()」にマッチさせたければ\を使って /\(.*\)/とします。
ただの「()」は「カッコの中のマッチした文字列をこっそり$1に突っ込んでお
いてください」という意味です。$1の1は、カッコの登場順の番号を表します。
例えば
$date = '2001/5/11 21:25:30';
$date =~ m/^(\d+)\/(\d+)\/(\d+) (\d+):(\d+):(\d+)/;
とすると、$1に「2001」が、$2に「5」が、$3に「11」が…$6に「30」が入り
ます。
なお、「\d」は数字を表す記号です。また「/」はそのまま書くと
m//のスラッシュと区別がつかなくなるので「\/」としてあります。これを
避けるためm//を「/」ではない任意の文字で囲む方法もあります。
$date =~ m@^(\d+)/(\d+)/(\d+) (\d+):(\d+):(\d+)@;
これだと@が区切りになるので「/」はそのままでよくなります。このときは
「m」は省略できません(なんか余計な説明加えちゃってかえって混乱させ
ちゃったかな…)。
> (@log = <IN>;とかforeach(0 .. $#data){}とか)
foreachのかわりにmap {} @data; を使うことを覚えたりするとさらにクセに
なりますよ。
再度お付き合いいただきありがとう御座います。考察2です(笑)。
なんかやたらと手強い正規表現ですが(最初の頃は謎の羅列でしたが)、片鱗をちょっと垣間見させていただいました。
$logpassword =~ /^\$1\$(.*)\$/
仰る通りに上記を解読してみると・・・。
まず、基本的に「$1$何か$」という文字列を評価し、「何か」の部分以外がマッチすれば、「.*」であるために「何かの部分が空文字列」でもひとまず真ということですね。
それで、「/^$1$/」の形であるために「最初が$1$のもの」を評価することになると。
その後、()があるので()内でマッチするものがあれば$1に代入しろ、と。ここでは()内が「.*」つまり「なんでもいい」ということなんで、結局「$1$」と「$」に挟まれた部分の文字列を$1に代入せよ、と言うことなんですね。なんで$1かっていうのは、()が1つ目だからであると。
ちょっと意訳しすぎてるところもありますが、おおざっぱに言うとこの正規表現の形はこんな感じでOKですかね?
ただ、またちょっと疑問というか確認したいことは、「^」はつまり「文字列の0文字目から」という意味になるのでしょうか?だとすると、n文字目の場合はどうなるんでしょうか?リファレンスにも書いてないようなんで・・・。まぁ、これは後学だから別の本を参照すべきですね。
¥のエスケープについてはちょっとかじってるのでなんとか理解できました。取得したIPを分けるときなんかにsplit(/\./,$ENV{'りもーとあど'})とするのと一緒ですね。
dは・・・。フォーマットの時のsprintf("%.3d",$data)みたいなものでしょうか?C言語では、まぁdは整数fは小数点とかありましたけど、あれと一緒ですかね?表記方法も一緒っぽいし。
んで合ってたら結論ですが、結局この質問って「正規表現なんたら」の問題だったわけですね・・・。CGIとか暗号解読とか、全然関係ないし・・・。正規表現恐るべし、祖国統一万歳ですね。
それじゃ、これで(この質問は)最後かと思いたいんですが、確認をよろしくお願いします(メールじゃないんでもちろんどなたでも。是非お願いします)。
No.3
- 回答日時:
そういう解釈でよろしいと思います。
「n文字目」についてですが、/^.{n}\$1\$/ ですね。{}で繰り返す数を
指定します。でもあまり使うことはないですね。固定で先頭から何文字か
わかってる場合はsubstrで切り出したりできますしね。
substr($xxx, n) =~ /^\$1\$/ ともできます。…でも書いてないのは
リファレンスとしていかがなものか。
dはdecimal, 10進数の略です。sprintfのものも同じ語源だと思います。
Perlの正規表現はさらにものすごく多機能です。ゆっくり覚えていくことを
お薦めします。
どうもありがとう御座いました。複数回に渡って丁寧に説明して下さり、とてもわかりやすく勉強になりました。
教えて下さったことをしっかり頭にたたき込んで、これからも勉強していきたいと思います。
今回は本当に助かりました。心より御礼申し上げます。
悠夜
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・街中で見かけて「グッときた人」の思い出
- ・「一気に最後まで読んだ」本、教えて下さい!
- ・幼稚園時代「何組」でしたか?
- ・激凹みから立ち直る方法
- ・1つだけ過去を変えられるとしたら?
- ・【あるあるbot連動企画】あるあるbotに投稿したけど採用されなかったあるある募集
- ・【あるあるbot連動企画】フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?
- ・映画のエンドロール観る派?観ない派?
- ・海外旅行から帰ってきたら、まず何を食べる?
- ・誕生日にもらった意外なもの
- ・天使と悪魔選手権
- ・ちょっと先の未来クイズ第2問
- ・【大喜利】【投稿~9/7】 ロボットの住む世界で流行ってる罰ゲームとは?
- ・推しミネラルウォーターはありますか?
- ・都道府県穴埋めゲーム
- ・この人頭いいなと思ったエピソード
- ・準・究極の選択
- ・ゆるやかでぃべーと タイムマシンを破壊すべきか。
- ・歩いた自慢大会
- ・許せない心理テスト
- ・字面がカッコいい英単語
- ・これ何て呼びますか Part2
- ・人生で一番思い出に残ってる靴
- ・ゆるやかでぃべーと すべての高校生はアルバイトをするべきだ。
- ・初めて自分の家と他人の家が違う、と意識した時
- ・単二電池
- ・チョコミントアイス
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
Perlのエラーについてご教授く...
-
perlの構文でカンマの意味が分...
-
Perlで、「が」を、「...
-
Perlでの文字変換(置換)について
-
このファイルを開く方法で困っ...
-
perlについて
-
PERL
-
C言語の問題について
-
ちょうどn文字の連続にマッチす...
-
PerlでUTF-8のファイルの文字列...
-
3から100までの素数を配列に入...
-
Perl 改行処理 と カンマ区切り
-
ラズベリーパイ初心者です。 ラ...
-
Perl言語について。
-
ファイルをディレクトリ分配の...
-
アルファベットに付いて質問し...
-
#!/usr/bin/perlで書きだしたCG...
-
perlのflock関数でロックをかけ...
-
AI sisterとは、偽物の人ですか?
-
bashスクリプト
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
テキストファイルで提出とは?
-
INDIRECT 横に再度抽出したい
-
perlをバージョンアップしたら...
-
openした後、closeしないでプロ...
-
アルファベットに付いて質問し...
-
Strawberry Perl for Windows ...
-
bashスクリプト
-
Perlのエラーについてご教授く...
-
Perlで特定文字列から特定文字...
-
画像が表示でnull; this.src
-
Wallpaper Engineでおすすめの...
-
Perl言語について。
-
perl LWPでURLにアクセスした時...
-
Perlで時間の計算
-
Perlで、「が」を、「...
-
ファイルアイコンの左下に緑の□...
-
Perl の外部モジュールの利用方法
-
このファイルを開く方法で困っ...
-
perlで2次元配列をサブルーチ...
-
Windows10においての『Perl』の...
おすすめ情報