[PHP]10進数を任意の文字を使って62進数などのn進数に相互変換する(基数変換)

Pocket

短縮URL等を発行する際に、データベースなどのIDをURLと関連付けて使うことが多いですが、単純に数字だけのIDを使うと多くの桁数を消費してしまいます。
0-9 に a-f を加えて一桁で16個まで表現できる16進数を使えば少し桁数を節約することができます。

この場合 a が 10 を表し、f が 15 となり、10 が 16 を意味します。
PHP で16進数の変換を行うには hexdec() や dechex() を使います。

16進数ではアルファベットの「f」までしか使いませんでしたが、残りの「g-z」を加えればもっと多くの数値を表現できます。また、URL は大文字小文字を区別するので、「A-Z」を更に加えて62進数にすると一桁だけでもかなりの情報量を扱えるようになります。

<?php
$char = array_merge(range('0','9'), range('a', 'z'), range('A', 'Z'));

$number = 1000000;
echo encode($number, $char) . ', ';

$str = "Test";
echo decode($str, $char);

function encode($number, $char){
	$result = "";
	$base = count($char);
	
	while($number > 0){
		$result = $char[ fmod($number, $base) ] . $result;
		$number = floor($number / $base);
	}
	return ($result == "" ) ? 0 : $result;
}

function decode($str, $char){
	$result = 0;
	$base = count($char);
	$table = array_flip($char);
	$digit = array_reverse(preg_split('//', $str, -1, PREG_SPLIT_NO_EMPTY));

	foreach($digit as $i => $value){
		if(!isset($table[$value])) return false;
		$result += pow($base, $i) * $table[$value];
	}
	
	return $result;
}

[実行結果]

4c92(1000000の62進数化)
13163621(「Test」の10進数化)

変数 char に代入された文字列を使って n 進数に変換します
基数は文字列の種類によって自動的に決められます。

ちなみにこの 62進数に更に2文字を加えたのが Base64 というもので、
PHP では base64encode() などの関数として利用できます。
Base64 は上記の英数字に加えて「+」と「/」が使われます。また、4文字ずつ区切って変換するので余った部分は「=」で埋められます。
Base64 で短縮URLを作る場合は「+」や「/」をURLとして問題の起きない「_」などの文字に置き換える必要があります。

[参考]
http://q.hatena.ne.jp/1222172924/186107/#i186107

Similar Posts:




コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です