月別アーカイブ: 2014年4月

62進数

Pythonで62進数を作ってみた。
なぜ62進数かって?
それは英数字全部合わせて62文字だから。
Base64とか+とか/とか入って嫌じゃないですかー。

さっそく書いてみた。

def _make_use_chars_base_62():
    return [str(i) for i in xrange(0, 10)] + \
           [chr(i) for i in xrange(ord('a'), ord('z')+1)] + \
           [chr(i) for i in xrange(ord('A'), ord('Z')+1)]

def encode_base_62(decimal):
    base_62_str = ''
    use_chars = _make_use_chars_base_62()
    while True:
        base_62_str = use_chars[decimal % 62] + base_62_str
        decimal -= decimal % 62
        decimal /= 62
        if decimal == 0:
            break
    return base_62_str

def decode_base_62(base_62_str):
    decimal = 0
    use_chars = _make_use_chars_base_62()
    for c in base_62_str:
        decimal *= 62
        decimal += use_chars.index(c)
    return decimal

もうちょっとキレイで速いコード書けそうだけど、まあいいや。時には妥協も必要さ。
encodeの方のループ抜ける所はdo-whileで書きたいけど、Pythonにはdo-whileないんだよね…

動かしてみよう。

>>> encode_base_62(0)
'0'
>>> encode_base_62(10)
'a'
>>> encode_base_62(36)
'A'
>>> encode_base_62(62)
'10'
>>> encode_base_62(124)
'20'
>>> encode_base_62(100000000)
'6LAze'
>>> decode_base_62('6LAze')
100000000
>>> decode_base_62('0')
0

なんとなく大丈夫そう。
本当はきっちりテストコード書くべきだけど、まあいいや。
62進数、というより英数字62文字で数値を表現したい場合は時々出てくるので、その時にきっちり検証しておこう。

Pythonでキューを作ってみる

プログラマたるもの、暇な時はアルゴリズムとデータ構造で時間を潰すべきと言えよう。
ということで、Pythonでキューを作ってみた。
プログラマたるもの、キューくらいサクッと書けないといけないね。

class OresamaQueue(object):
  def __init__(self):
    self._buffer = []

  def dequeue(self):
    if len(self._buffer) > 0:
      return self._buffer.pop()
    else:
      return None

  def enqueue(self, obj):
    self._buffer = [obj] + self._buffer

解説するとこもないくらい単純なキューの実装だ。
Pythonのリストにはリストの末尾を削除しつつその値を返してくれるpop()というステキメソッドがあるので、dequeueは楽勝で書けた。
enqueueもPythonではリスト同士を足し合わせると1つのリストに合体してくれるので、[obj]で受け取った値を配列にして既存の配列と足し算しちまえばいい。

テストをしよう。手動で。

>>> import OresamaQueue
>>> q = OresamaQueue()
>>> q.enqueue(1)
>>> q.enqueue(2)
>>> q.enqueue(3)
>>> q.dequeue()
1
>>> q.dequeue()
2
>>> q.dequeue()
3
>>> q.dequeue()
>>> q.dequeue() is None
True

うん、見事なまでの先入れ先出し、まごうことないキュー。

ま、Pythonには最初からQueueモジュールがあるので、そっち使えばいいんだけどね。

PythonでSHA-3を使おう

新しい一方向ハッシュ関数SHA-3をPythonで使いたくなったのでGoogle様にお伺いを立てるとpysha3を使えば良いとのお返事が。
そこでさっそくインストールしてみる。

$ pip install pysha3

CのSHA-3ライブラリのラッパーになってるようだ。
速度も期待できるかな。
さっそく使ってみる。

$ python
>>> import hashlib
>>> import sha3
>>> hashlib.sha3_256('Hello, world!').hexdigest()
'b6e16d27ac5ab427a7f68900ac5559ce272dc6c37c82b3e052246c82244c50e4'
>>> hashlib.sha3_512('Hello, world!').hexdigest()
'101f353a4727cc94ef81613bb38a807ebc888e2061baa4f845c84cd3c317f3430fda3dbeb44010844b35bccc8e190061d05b4d002c709615275a44e18e494f0c'

import sha3するとhashlibにパッチ当ててくれる。
monkey patchとかいうやつだ。
こいつのお陰でhashlibでSHA-2とかと同じ書き方でSHA-3が計算できるので便利。
ちょっとお行儀悪い気もするけど…

Pythonのリスト内包表記がステキ

Pythonにはリスト内包表記というステキな機能がある。
最近かなり活用しているので、メモっとく。

テストデータとかで、大量の連番リストが欲しいとかよくあるよね。
馬鹿正直に書くとこうなる。

a = []
for i in xrange(0, 100):
    a.append(i)

リスト内包表記で書くとこうなる。

a = [i for i in xrange(0, 100)]

一行で書けちゃった。

これだけだと短く書けるだけじゃん、となるけど、さらに条件式も入れられる。
例えば、既存のリストから、偶数だけを抜き出すコードを書いてみる。

b = [i for i in a if i % 2 == 0]

条件式が書けるため、リストから条件に合うものを抜き出す処理がサクッとかけて、実に便利だ。
Python使うなら覚えておいて損はないと思う。

PyCryptoでAES暗号を使ってみた

PythonでAES暗号を取り扱わなければならなくなったので備忘録代わりにメモ。
まずはPyCryptoをインストール。

$ pip install PyCrypto

それではAESの暗号化、復号化してみるよ。
こんなコード書いてみた。
CBCモードで初期ベクトルは乱数を使ってる。

import os
import hashlib

from Crypto.Cipher import AES

# key and initial vector
secret_key = hashlib.sha256('This is secret passphrase.').digest()
iv = os.urandom(16)

# plain text
plain_text = 'A' * 16

# encrypt
aes = AES.new(secret_key, AES.MODE_CBC, iv)
encrypt_data = aes.encrypt(plain_text)

# decrypt
aes = AES.new(secret_key, AES.MODE_CBC, iv)
decrypt_data = aes.decrypt(encrypt_data)

# output result
print 'plain text: %s' % (plain_text)
print 'initial vector: %s' % (iv.encode('hex'))
print 'encrypt: %s' % (encrypt_data.encode('hex'))
print 'decrypt: %s' % (decrypt_data)

そいでは実行してみましょう。

$ python test001.py
plain text: AAAAAAAAAAAAAAAA
initial vector: 1e37825a3af0345564c9694c4e0a65e7
encrypt: b631aa2387fc7870b38e2008b44e5c0e
decrypt: AAAAAAAAAAAAAAAA

$ python test001.py
plain text: AAAAAAAAAAAAAAAA
initial vector: c881768a26d219bde12e708e588d5e3b
encrypt: d3fb0ac082c734c0b66e58c501c40e74
decrypt: AAAAAAAAAAAAAAAA

$ python test001.py
plain text: AAAAAAAAAAAAAAAA
initial vector: eedff20172c9712f1493ca0d1b482b33
encrypt: 353823f2a4d25e7f3050e0d99e079538
decrypt: AAAAAAAAAAAAAAAA

うん、ちゃんと動いてるみたい。