Python SyntaxError Programming を解析してみた
id:TAKESAKO の 「Python SyntaxError Programming」が凄いです.
http://developer.cybozu.co.jp/takesako/2010/05/python-syntaxer.html
#!/usr/bin/python _=-~-~(()>[]);_,__=_*_,_**_-~-~_;___='%'+`SyntaxError`[_];exec''+___*(__+~-~_)%(_*_^-~__,_*_-~__,~__*__/~_,~-~_*~_,_-__^~-~_*_,-~-~__,~-_*_,_/_^~_*~_,_-~-~_*_,_-~-~_*_,_|~-~_*~_,_+__+__/_,__,~_&_*_,__+_|_*_,_-__^~-~_*_,__^~-_*_,_|~-~_*~_,~-~_*~_,-~__,-~-~__)
これで,
「Hello, Python!」
と表示されます.
凄すぎてどうなってるのか全然わかりません><
で,頑張って解析してみました.
まずは,文ごとに分ける
; で一行にされているので,まずは改行して見やすくしてみます.
_=-~-~(()>[]); _,__=_*_,_**_-~-~_; ___='%'+`SyntaxError`[_]; exec''+___*(__+~-~_)%(_*_^-~__,_*_-~__,~__*__/~_,~-~_*~_,_-__^~-~_*_,-~-~__,~-_*_,_/_^~_*~_,_-~-~_*_,_-~-~_*_,_|~-~_*~_,_+__+__/_,__,~_&_*_,__+_|_*_,_-__^~-~_*_,__^~-_*_,_|~-~_*~_,~-~_*~_,-~__,-~-~__)
まったく見やすくならないですね!! やりましたね!!
まずは1行目を解析してみる
_=-~-~(()>[]);
まず,_ に代入をしているのはわかります.
なので右辺を解析してみます.
-~-~(()>[]);
まずは,- も ~ も演算子なので確固のついている () > [] が先に処理されます.
で,空のタプルと空のリストを比較しています.
iPython で実行してみると
>>> () > []
True
となります.
ちなみに
>>> () < [] False >>> () == [] False >>> () is [] False >>> () in [] False
という結果になります.
これは Python の決め事で,昔の Guido は何でも比較出来るのが正しいと考えてたみたいです.
(Python3.0 では比較出来ないみたいです.)
で,話しを戻すと
-~-~True;
になっているわけですね.
で,~ 記号でビット反転されています.
ビット反転が良くわからなかったのですが,
http://ja.wikipedia.org/wiki/2%E3%81%AE%E8%A3%9C%E6%95%B0
ここを id:nishiohirokazu に教えてもらってわかりました!!
で,True の数値表現は 1 なので
>>> int(True) 1 >>> ~1 -2 >>> --2 2 >>> ~2 -3 >>> --3 3
と,言う事で _ に 3 を代入している事がわかりました.
2行目を解析してみる
こうなってくると,2行目が見えてきました.
_,__=_*_,_**_-~-~_;
また代入をしているのですが,「,」 が両辺にあるので多項代入だとわかります.
で,右辺をまずはさきほど求めた 3 でおきかえてみます.
_,__=3*3,3**3-~-~3;
になります.
_,__=3*3,3**3-~-~3;
計算すると
_,__=9,32;
になります.
これで,この時点でそれぞれ変数に
_ = 9
__ = 32
が,入っている事がわかります.
3行目を解析してみる
___='%'+`SyntaxError`[_];
まずは代入なので右辺を見ていきます.
で,判明している _ に 9 を入れてみます.
___='%'+`SyntaxError`[9];
で,バッククートは括れば評価結果を取得できるので SyntaxError を評価すると
(これも Python3.0 では repr 関数に置きかわりました)
>>> `SyntaxError` "<type 'exceptions.SyntaxError'>"
と,文字列を取得できます.
___='%'+"<type 'exceptions.SyntaxError'>"[9];
で,その文字列の配列の9要素目なので
「c」が取得できます.
___='%'+'c';
___='%c';
で,結果として
___ = '%c'
が入っている事になります.
4行目を解析してみる
exec''+___*(__+~-~_)%(_*_^-~__,_*_-~__,~__*__/~_,~-~_*~_,_-__^~-~_*_,-~-~__,~-_*_,_/_^~_*~_,_-~-~_*_,_-~-~_*_,_|~-~_*~_,_+__+__/_,__,~_&_*_,__+_|_*_,_-__^~-~_*_,__^~-_*_,_|~-~_*~_,~-~_*~_,-~__,-~-~__)
ここまでで,
_ = 9
__ = 32
___ = '%c'
が判明しているので,すべて置き換えてみます.
exec''+%c*(32+~-~9)%(9*9^-~32,9*9-~32,~32*32/~9,~-~9*~9,9-32^~-~9*9,-~-~32,~-9*9,9/9^~9*~9,9-~-~9*9,9-~-~9*9,9|~-~9*~9,9+32+32/9,32,~9&9*9,32+9|9*9,9-32^~-~9*9,32^~-9*9,9|~-~9*~9,~-~9*~9,-~32,-~-~32)
あとは計算してみると……
exec''+'%c'*(21)%(112,114,105,110,116,34,72,101,108,108,111,44,32,80,121,116,104,111,110,33,34)
となります.
で,
exec''+'%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c'%(112,114,105,110,116,34,72,101,108,108,111,44,32,80,121,116,104,111,110,33,34)
と,文字コードから文字列を作りだしていて……
exec''+'print"Hello, Python!"'
となっていて
「Hello, Python!」
と表示されます.
以上,解析結果としては,id:TAKESAKO が変態すぐるという事がわかりました><