「パスワード暗号化について(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で質問しましょう!
似たような質問が見つかりました
- 国家公務員・地方公務員 公務員試験の数的処理で苦戦しています。 1 2023/01/30 08:56
- 発達障害・ダウン症・自閉症 私は幼い頃から周りの子と変わったところがあり社会人になってからも仕事が長続きせず上手くいかないことだ 3 2022/08/26 13:24
- 大学受験 国立受験 11月からの大逆転劇を起こすには 7 2022/11/14 19:24
- 数学 どっちと思いますか 4 2022/10/10 11:16
- Visual Basic(VBA) Selenium.ChromeDriverの使い方について 7 2022/09/22 06:43
- Visual Basic(VBA) 【前回の続きです、ご教示ください】VBAの記述方法がわかりません。 2 2022/08/16 16:44
- 大学受験 身長187cmです。 大学受験で南極老人という人の勉強方法が書かれた本を買いました。ミスターステップ 3 2022/08/02 20:49
- その他(プログラミング・Web制作) Pythonを用いたフラッシュ暗算ソフトの開発に必要なもの 2 2023/01/29 02:22
- 数学 数的処理の勉強方法について 最初数的処理の勉強を始めた学生です。 パターン暗記というものが良いらしい 3 2023/04/03 11:54
- システム CPUの問題について 2 2022/07/09 12:04
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
perlのプログラミング 部分入れ...
-
Strawberry Perl for Windows ...
-
アルファベットに付いて質問し...
-
Perlで同じフォルダにある任意...
-
perlでリテラル値はメモリにど...
-
ペプシコーラとコカ・コーラとD...
-
perlをバージョンアップしたら...
-
openした後、closeしないでプロ...
-
#!/usr/bin/perlで書きだしたCG...
-
Perlのエラーについてご教授く...
-
perlのflock関数でロックをかけ...
-
AI sisterとは、偽物の人ですか?
-
perlで2次元配列をサブルーチ...
-
perlのrequireの動き方について...
-
perlについての質問
-
Blenderについて
-
Perl の外部モジュールの利用方法
-
perl このテキストファイルを簡...
-
Perlでファイルの末尾から指定...
-
秀丸での一括変換について
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
テキストファイルで提出とは?
-
openした後、closeしないでプロ...
-
perlをバージョンアップしたら...
-
INDIRECT 横に再度抽出したい
-
Perl の外部モジュールの利用方法
-
Perlで特定文字列から特定文字...
-
Perlのエラーについてご教授く...
-
bashスクリプト
-
Strawberry Perl for Windows ...
-
perlで2次元配列をサブルーチ...
-
TeraPadエディターの操作方法に...
-
アルファベットに付いて質問し...
-
perlのflock関数でロックをかけ...
-
ファイルアイコンの左下に緑の□...
-
perlプログラミング 空白行削除
-
Wallpaper Engineでおすすめの...
-
Perlで時間の計算
-
perlのrequireの動き方について...
-
perlでリテラル値はメモリにど...
-
画像が表示でnull; this.src
おすすめ情報