短縮URL等で使われるbase64(64進法)表記。
base10(10進法)へ戻したいことがたまにあります。
ただ、戻そうとしたら大きな数字(17桁以上)で、
計算に失敗するという。
かなり?苦戦したのでメモとして残したいと思います。
Google Apps Script (GAS)になります。
やりたいこと
- GASでbase64をbase10に変換
- base10にした時に17桁以上(2^54以上)でも対応
POINT
- 1文字ずつ変換
- 64進法から10進法に変換したらすぐに.ToFixed(0).ToString()
- 10進法の数字は下から10桁くらいずつ分けて処理、最後に結合
GAS スクリプト
引数はst_base64(64進法で書かれた文字列)、
戻り値は st_base10(10進法に換算して文字列にしたもの)
になります。
POINTの項にほとんど肝は書いてしまったので、
スクリプトを一気書きして終了にします。
function fn_base64url2base10str(st_base64){
// base64urlをbase10(文字列)へ変換
// Reference : https://ja.loveblade.org/361152-where-do-i-find-the-JVZRBG
var base64url_chars = ‘ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_’;
var split_digit = 10; // 計算時に大きな数字を避けるためこの桁数ごとに配列ar_base10に格納して計算させる(<16)
var st_base10; // 最終出力 10進法にした文字列
var ar_base10 = []; // split_digit桁ごと分けて格納する(桁数対応)。最後にjoinで繋げる↑
var st_base10_i; // base64のi文字目→base10に変換 * 64^桁目
var st_base10_i_j; // 上の文字の下からsplit_digit桁ずつの数字
for (var i = 0; i < st_base64.length ; i++){
// 上から1桁ずつ変換。桁も考慮して一気にbase10へ *POINT1*, *POINT2*
st_base10_i = (base64url_chars.indexOf(st_base64[i]) * Math.pow(64, (st_base64.length – i – 1))).toFixed(0).toString();
// 下から10桁ずつar_base10に格納 *POINT3*
for (var j = 1; j <= Math.ceil(st_base10_i.length / split_digit); j++ ){
if (j > ar_base10.length){
// ar_base10の要素数が足りない場合は頭に0を入れる
ar_base10.unshift(0);
}
if (j == Math.ceil(st_base10_i.length / split_digit) && st_base10_i.length % split_digit > 0){
// 頭の桁で且つst_base10_iの桁数がsplit_digitで割り切れない場合
// 先頭から必要な桁を取り出す
st_base10_i_j = st_base10_i.substr(0, st_base10_i.length % split_digit);
}else{
// 途中のsplit_digit桁を取り出す
st_base10_i_j = st_base10_i.substr(st_base10_i.length – j * split_digit, split_digit);
}
// 同じ桁同士を足す
ar_base10[ar_base10.length – j] += Number(st_base10_i_j);
// 足し算をした結果10^split_digit以上の場合は繰り上げ処理する(一個手前の要素に足す)
if (ar_base10[ar_base10.length – j] >= Math.pow(10,split_digit)){
if (j + 1 > ar_base10.length){
// ar_base10の要素数が足りない場合は頭に0を入れる
ar_base10.unshift(0);
}
ar_base10[ar_base10.length – j – 1] += Math.floor(ar_base10[ar_base10.length – j]/Math.pow(10,split_digit));
ar_base10[ar_base10.length – j] = ar_base10[ar_base10.length – j] % Math.pow(10,split_digit);
}
}
}
// ar_base10[0]は文字列に、他はsplit_digit桁の文字列に直す。
// (ただ繋げると桁が足りない時NGなので)
for(i = 0; i < ar_base10.length; i++){ // 文字列に直す。 ar_base10[i] = ar_base10[i].toString(); // i=0でない場合は10桁にする if (i > 0){
ar_base10[i] = (“00000000000000000000” + ar_base10[i]).slice(-1*split_digit);
}
}
// ar_base10の配列を繋げて完成
st_base10 = ar_base10.join(“”);
// Logger.log(st_base10);
return st_base10;
}
Reference
- Base64 at Wikipedia
- 画像のInstagramメディアIDはどこにありますか at LoveBlade (なんかちょっと怪しい)
余談
これ、Instagramのmedia-idをURLから取得するために取り掛かりました。
しかし、目的のjsonがエラーできて取得できない事件(笑)!
とりあえず、成果物としてUPします。
Leave a Reply