2010/10/18

ワンライナーで自分の名前を表示する(8しばり)

Python Recipesに戻る
Text Recipesに戻る

Release:1.0
Date:October 18, 2010

テスト環境
OS: Ubuntu10.10

Python2系

Python2.6.6及び、Python2.5.2でテストを行ないまいた。

はじめに

私の尊敬している西尾さんが、7しばりで自分の名前を表示するコードを書いて
いらっしゃったので自分もしてみたくなりました。

7しばりではなく、末広がりの8で頑張ってみようと思います。

ちなみに、西尾さんのコードはこれです

$ python -c "print ''.join(chr(x) for x in(77777/7/77, 77+777/7, 77-7%~77, 7-~777-7*77, ~7%77+~-77, 77^77+77, ~7&77+77, -777/~7)).decode('cp932')"
最後の「.decode(‘cp932’)」は私のOSがUbuntuなので、文字化け対策のために自分で書き加えたものです。
Windowsの場合はdecode~はいらないと思います。

Note

このコードのライセンスがわかりませんでした(TT)
もし、不具合があった場合は削除しますので、ご連絡をおねがいします。

手順1

まずは、自分の名前を1コードずつに区切り、文字コードに対応する整数を導き出します。
文字コードは UTF-8 にしてあります。
ord_num = tuple(map(ord, u"込山伊典".encode('utf8')))
print(ord_num)
(232, 190, 188, 229, 177, 177, 228, 188, 138, 229, 133, 184)

Note

Python2.6では
from __future__ import unicode_literals
とすると文字列がすべてunicode扱いになるので、 u が省けます。

手順2 8で表すことができる数を洗い出す

8という整数だけで、ord_nameのlistにある整数を表さないといけません。
そこで、8という整数ではどのような整数をあらわせるか洗い出してみましょう。
~8で       -9     -0b1001
~8/8で     -2     -0b10
8/~8で     -1     -0b1
8/8で       1      0b00000001
88%~-8      4      0b00000100
~8%8で      7      0b00000111
8で         8      0b00001000
888/88で    10     0b00001010
88/8で      11     0b00001011
~-88/~-8で  12     0b00001100
888/8/8で   13     0b00001101
8+8で       16     0b00010000
8+8+8で     24     0b00011000
88^88+8で   56     0b00111000
8*8で       64     0b01000000
~8%88で     79     0b01001111
~8&88で     80     0b01010000
88          88     0b01011000
88+8        96     0b01100000
8888/88で   101    0b01100101
888/8で     111    0b01101111
88+88       176    0b10110000

このくらい分かれば十分かな???

手順3 手順2を基本に整数を導き出す

まずは、ord_num[0]の232を8だけで表す。

232 0b11101000

これは、
88+88 176 0b10110000
88 88 0b01011000
との排他的論理和でできそうだ。
>>> 88^88+88
232

ビンゴ!!

残り11個
(88^88+88, 190, 188, 229, 177, 177, 228, 188, 138, 229, 133, 184)

ord_num[1]の190を8だけで表す。

190 0b10111110

これは単純に、111に88を足し9を引いても短く書ける
よって、 ~8+88+888/8
>>> ~8+88+888/8
190
残り10個
(88^88+88, ~8+88+888/8, 188, 229, 177, 177, 228, 188, 138, 229, 133, 184)

ord_num[2]の188を8だけで表す。

188 0b10111100

これも単純に、101に88を足し9をを引いて8を足す。
うまいやり方が思いつかない。
よって、 ~8+88+8888/88+8
>>> ~8+88+8888/88+8
188
残り9個
(88^88+88, ~8+88+888/8, ~8+88+8888/88+8, 229, 177, 177, 228, 188, 138, 229, 133, 184)

ord_num[3]の229を8だけで表す。

229 0b11100101

ord_num[0]の232に10を足し7をを引く。
(88^88+88)-(888/88-~8%8)
カッコをつけなくてはいけないので却下。

まずは、88と101の排他的論理和を求める。

88 88 0b01011000
88+888/8/8 101 0b01100101

求められる数は
88^88+888/8/8 61 0b00111101

あとは、88を足して出来上がり!

>>> 88^88+888/8/8+88
229
残り8個
(88^88+88, ~8+88+888/8, ~8+88+8888/88+8, 88^88+888/8/8+88, 177, 177, 228, 188, 138, 229, 133, 184)

ord_num[4]の117を8だけで表す。

117 0b1110101

これは簡単!!
176に1を足せばできる。

88+88+8/8

>>> 88+88+8/8
177
残り7個
(88^88+88, ~8+88+888/8, ~8+88+8888/88+8, 88^88+888/8/8+88, 88+88+8/8, 177, 228, 188, 138, 229, 133, 184)

ord_num[5]も117なので省略。

残り6個
(88^88+88, ~8+88+888/8, ~8+88+8888/88+8, 88^88+888/8/8+88, 88+88+8/8, 88+88+8/8, 228, 188, 138, 229, 133, 184)

ord_num[6]は228。

これは、229に1引いたものだから。

229 88^88+888/8/8+88
1 8/8
よって
88^88+888/8/8+88+8/8
>>> 88^88+888/8/8+88-8/8
228
残り5個
(88^88+88, ~8+88+888/8, ~8+88+8888/88+8, 88^88+888/8/8+88, 88+88+8/8, 88+88+8/8, 88^88+888/8/8+88+8/8, 188, 138, 229, 133, 184)

ord_num[7]は188。

188 0b10111100
なんか、88+88 176 0b10110000
に近い感じがする。
~-88/~-8の12を足せば完成だ!!
論理和 | のほうが、短いのでこれを適用して。

88+88|~-88/~-8

>>> 88+88|~-88/~-8
188
残り4個
(88^88+88, ~8+88+888/8, ~8+88+8888/88+8, 88^88+888/8/8+88, 88+88+8/8, 88+88+8/8, 88^88+888/8/8+88+8/8, 88+88|~-88/~-8, 138, 229, 133, 184)

ord_num[8]は138。

138 0b10001010
8888/88で 101 0b01100101
これをベースに考えてみる。だんだん面倒くさくなってきた。
これに11と16を足せば完成だ。

888/8+88/8+8+8

>>> 888/8+88/8+8+8
138
残り3個
(88^88+88, ~8+88+888/8, ~8+88+8888/88+8, 88^88+888/8/8+88, 88+88+8/8, 88+88+8/8, 88^88+888/8/8+88+8/8, 88+88|~-88/~-8, 888/8+88/8+8+8, 229, 133, 184)

ord_num[9]の229は前にも書いたので省略。

>>> 88^88+888/8/8+8
229
残り2個
(88^88+88, ~8+88+888/8, ~8+88+8888/88+8, 88^88+888/8/8+88, 88+88+8/8, 88+88+8/8, 88^88+888/8/8+88+8/8, 88+88|~-88/~-8, 888/8+88/8+8+8, 88^88+888/8/8+8, 133, 184)

ord_num[10]は133。

133 0b10000101
8888/8 111 0b01101111
これをベースに考えてみる。
8+8+8 24 0b00011000
を足してみると、135 0b10000111
あとは2を引いてやるだけだ。

888/8+8+8+8+~8/8

>>> 888/8+8+8+8+~8/8
133
残り1個
(88^88+88, ~8+88+888/8, ~8+88+8888/88+8, 88^88+888/8/8+88, 88+88+8/8, 88+88+8/8, 88^88+888/8/8+88+8/8, 88+88|~-88/~-8, 888/8+88/8+8+8, 88^88+888/8/8+88, 888/8+8+8+8+~8/8, 184)

ord_num[11]の184は簡単だ。

88+88 176 0b10110000
に8を足してやるだけでいい。

88+88+8

>>> 88+88+8
184
残り0個
(88^88+88, ~8+88+888/8, ~8+88+8888/88+8, 88^88+888/8/8+88, 88+88+8/8, 88+88+8/8, 88^88+888/8/8+88+8/8, 88+88|~-88/~-8, 888/8+88/8+8+8, 88^88+888/8/8+88, 888/8+8+8+8+~8/8, 88+88+8)

完成!!

これを西尾さんのはforで回してありましたが、map()という便利な関数が増えているので、これを使って

>>> print(''.join(map(chr, (88^88+88, ~8+88+888/8, ~8+88+8888/88+8, 88^88+888/8/8+88, 88+88+8/8, 88+88+8/8, 88^88+888/8/8+88-8/8, 88+88|~-88/~-8, 888/8+88/8+8+8, 88^88+888/8/8+88, 888/8+8+8+8+~8/8, 88+88+8)))).decode('utf8')
込山伊典
ちゃんと出来ています!!!
長ったらしいコードになってしまったのは、自分がビット演算をよく理解していないためです、、、

ちなみに、ターミナルや端末からは、

$ python -c "print(''.join(map(chr, (88^88+88, ~8+88+888/8, ~8+88+8888/88+8, 88^88+888/8/8+88, 88+88+8/8, 88+88+8/8, 88^88+888/8/8+88-8/8, 88+88|~-88/~-8, 888/8+88/8+8+8, 88^88+888/8/8+88, 888/8+8+8+8+~8/8, 88+88+8)))).decode('utf8')"

で表示されます。コマンドとしてはちょっと長すぎですが、、、

Python3系

※Python3.1.2でテストを行ないました。

手順1

まずは、自分の名前を1コードずつに区切り、文字コードに対応する整数を導き出します。
文字コードは UTF-8 にしてあります。
まだPython3の勉強はあまりしていないのですが、byte文字に対しては ord() しなくても
文字コード1文字の整数が求められるようです。(※要確認)

ord() はunicode文字列のみで動作するみたいです(※要確認)

ord_num = tuple("込山伊典".encode('utf8'))
print(ord_num)
(232, 190, 188, 229, 177, 177, 228, 188, 138, 229, 133, 184)

手順2

2系の手順2と同じようにします。

残り0個
(88^88+88, ~8+88+888/8, ~8+88+8888/88+8, 88^88+888/8/8+88, 88+88+8/8, 88+88+8/8, 88^88+888/8/8+88+8/8, 88+88|~-88/~-8, 888/8+88/8+8+8, 88^88+888/8/8+88, 888/8+8+8+8+~8/8, 88+88+8)

完成!!

Python3では bytes() という関数があります。
これはunicode以外の文字列を扱うときに使うものだと思います。
これを使えば、sourceを(2系の) chr() した上で join することができるのだと、
たぶん思います(※要確認)
2系の unichr() は3系の chr() で置き換わっていますので、byte文字列に使う
ことができなくなっているのです。

このとき、注意すべきは、 .decode() はバイト文字にしか適用てきないということです。

Python2系では

print(u'あ'.encode('cp932')).decode('cp932')
あ

などと、プリント文のあとにも適用できましたが、Python3系では必ず、byte文字のあとに適用しましょう。

print('あ'.encode('cp932').decode('cp932'))
あ

んん〜いいたいことがうまく伝えられてないような、、、
詳しくは、ページ最下部にある 参考・引用 をご覧ください。

print(bytes((88^88+88, ~8+88+888//8, ~8+88+8888//88+8, 88^88+888//8//8+88, 88+88+8//8, 88+88+8//8, 88^88+888//8//8+88-8//8, 88+88|~-88//~-8, 888//8+88//8+8+8, 88^88+888//8//8+88, 888//8+8+8+8+~8//8, 88+88+8)).decode('utf8'))

ちなみに、ターミナルや端末からは、

$ python -c "print(bytes((88^88+88, ~8+88+888//8, ~8+88+8888//88+8, 88^88+888//8//8+88, 88+88+8//8, 88+88+8//8, 88^88+888//8//8+88-8//8, 88+88|~-88//~-8, 888//8+88//8+8+8, 88^88+888//8//8+88, 888//8+8+8+8+~8//8, 88+88+8)).decode('utf8'))"

で表示されます。コマンドとしてはちょっと長すぎですが、、、

2系と3系をどちらもいれていらっしゃる場合は、

$ python3 -c "print(bytes((88^88+88, ~8+88+888//8, ~8+88+8888//88+8, 88^88+888//8//8+88, 88+88+8//8, 88+88+8//8, 88^88+888//8//8+88-8//8, 88+88|~-88//~-8, 888//8+88//8+8+8, 88^88+888//8//8+88, 888//8+8+8+8+~8//8, 88+88+8)).decode('utf8'))"

おわりに

Python3でのやり方はtwitterで @ucq さんに教えていただきました!!
親切に教えていただきありがとうございます!

参考・引用

Note

0 件のコメント:

コメントを投稿