web-dev-qa-db-ja.com

Base 62変換

整数をベース62にどのように変換しますか(16進数と同様ですが、これらの数字は「0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ」です)。

私はそれのための良いPythonライブラリを見つけようとしましたが、それらはすべて文字列の変換に専念しているようです。Python base64モジュールは文字列と1桁の数字を4文字に変換します。URL短縮サービスが使用するものに似たものを探していました。

75
mikl

このための標準モジュールはありませんが、それを実現するために独自の関数を作成しました。

BASE62 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

def encode(num, alphabet=BASE62):
    """Encode a positive number in Base X

    Arguments:
    - `num`: The number to encode
    - `alphabet`: The alphabet to use for encoding
    """
    if num == 0:
        return alphabet[0]
    arr = []
    base = len(alphabet)
    while num:
        num, rem = divmod(num, base)
        arr.append(alphabet[rem])
    arr.reverse()
    return ''.join(arr)

def decode(string, alphabet=BASE62):
    """Decode a Base X encoded string into the number

    Arguments:
    - `string`: The encoded string
    - `alphabet`: The alphabet to use for encoding
    """
    base = len(alphabet)
    strlen = len(string)
    num = 0

    idx = 0
    for char in string:
        power = (strlen - (idx + 1))
        num += alphabet.index(char) * (base ** power)
        idx += 1

    return num

エンコードとデコードに使用するアルファベットを指定できることに注意してください。 alphabet引数を省略した場合、コードの最初の行で定義された62文字のアルファベットが取得されるため、62ベースとの間でエンコード/デコードが行われます。

お役に立てれば。

PS-URL短縮サービスについては、0Ol1oIなどのわかりにくい文字をいくつか省く方がよいことがわかりました。したがって、URL短縮のニーズにこのアルファベットを使用します-"23456789abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"

楽しむ。

144

私もこれを行うためのスクリプトを書いたことがありますが、とてもエレガントだと思います:)

import string
# Remove the `_@` below for base62, now it has 64 characters
BASE_LIST = string.digits + string.letters + '_@'
BASE_DICT = dict((c, i) for i, c in enumerate(BASE_LIST))

def base_decode(string, reverse_base=BASE_DICT):
    length = len(reverse_base)
    ret = 0
    for i, c in enumerate(string[::-1]):
        ret += (length ** i) * reverse_base[c]

    return ret

def base_encode(integer, base=BASE_LIST):
    if integer == 0:
        return base[0]

    length = len(base)
    ret = ''
    while integer != 0:
        ret = base[integer % length] + ret
        integer /= length

    return ret

使用例:

for i in range(100):                                    
    print i, base_decode(base_encode(i)), base_encode(i)
44
Wolph

次のデコーダーメーカーは、合理的なベースで動作し、より整然としたループを持ち、無効な文字に遭遇すると明示的なエラーメッセージを表示します。

def base_n_decoder(alphabet):
    """Return a decoder for a base-n encoded string
    Argument:
    - `alphabet`: The alphabet used for encoding
    """
    base = len(alphabet)
    char_value = dict(((c, v) for v, c in enumerate(alphabet)))
    def f(string):
        num = 0
        try:
            for char in string:
                num = num * base + char_value[char]
        except KeyError:
            raise ValueError('Unexpected character %r' % char)
        return num
    return f

if __== "__main__":
    func = base_n_decoder('0123456789abcdef')
    for test in ('0', 'f', '2020', 'ffff', 'abqdef'):
        print test
        print func(test)
9
John Machin

最高の効率(Djangoなど)を探している場合は、次のようなものが必要です。このコードは、Baishampayan GhoseとWoLpHおよびJohn Machinの効率的なメソッドの組み合わせです。

# Edit this list of characters as desired.
BASE_ALPH = Tuple("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
BASE_DICT = dict((c, v) for v, c in enumerate(BASE_ALPH))
BASE_LEN = len(BASE_ALPH)

def base_decode(string):
    num = 0
    for char in string:
        num = num * BASE_LEN + BASE_DICT[char]
    return num

def base_encode(num):
    if not num:
        return BASE_ALPH[0]

    encoding = ""
    while num:
        num, rem = divmod(num, BASE_LEN)
        encoding = BASE_ALPH[rem] + encoding
    return encoding

事前に辞書を計算することもできます。 (注:文字列を使用したエンコードは、非常に長い数字であっても、リストを使用した場合よりも効率的です。)

>>> timeit.timeit("for i in xrange(1000000): base.base_decode(base.base_encode(i))", setup="import base", number=1)
2.3302059173583984

2.5秒未満で100万個の数字をエンコードおよびデコードします。 (2.2Ghz i7-2670QM)

7
Sepero

おそらくbase62ではなくbase64が必要でしょう。 URL互換バージョンがありますので、余分な2つのフィラー文字は問題になりません。

プロセスは非常に簡単です。 base64は6ビットを表し、通常のバイトは8を表すと考えてください。選択した64文字のそれぞれに000000から111111までの値を割り当て、3つのbase256バイトのセットと一致するように4つの値をまとめます。 3バイトごとに繰り返し、選択したパディング文字を最後にパディングします(通常は0が便利です)。

4

必要なのは、何かをエンコード/デコードするのではなく、短いIDを生成することだけである場合(URL短縮サービスについて言及しているため)、このモジュールが役立ちます。

https://github.com/stochastic-technologies/shortuuid/

Djangoフレームワークを使用する場合、Django.utils.baseconvモジュールを使用できます。

>>> from Django.utils import baseconv
>>> baseconv.base62.encode(1234567890)
1LY7VK

Base62に加えて、baseconvはbase2/base16/base36/base56/base64も定義しました。

2
heronotears

私のソリューションは次のとおりです。

def base62(a):
    baseit = (lambda a=a, b=62: (not a) and '0' or
        baseit(a-a%b, b*62) + '0123456789abcdefghijklmnopqrstuvwxyz'
                              'ABCDEFGHIJKLMNOPQRSTUVWXYZ'[a%b%61 or -1*bool(a%b)])
    return baseit()

説明

どのベースでも、すべての数値はa1+a2*base**2+a3*base**3...に等しいため、目標はすべてのasを見つけることです。

すべてのN=1,2,3...に対して、コードはbを「モジュロ化」することでaN*base**Nを分離し、b=base**(N+1)をすべてのasをNより大きくスライスします。すべてのaをスライスして、現在のaN*base**Nによって関数が再帰的に呼び出されるたびにNを減らすことにより、シリアルがaより小さくなるようにします。

Base%(base-1)==1したがって、base**p%(base-1)==1、したがって、q*base^p%(base-1)==qは、q==base-10を返すとき、1つだけ例外があります。その場合を修正するには、0を返します。この関数は、最初から0をチェックします。


利点

このサンプルでは、​​(除算ではなく)1つの乗算といくつかのモジュラス演算のみがあり、すべて比較的高速です。

2
Shu ba

ここで他の人の投稿から大きな恩恵を受けました。 python元々Djangoプロジェクトのコードが必要でしたが、それ以来node.jsに目を向けてきました。ここにjavascript version Baishampayan Ghoseが提供したコード(エンコード部分)。

var ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

function base62_encode(n, alpha) {
  var num = n || 0;
  var alphabet = alpha || ALPHABET;

  if (num == 0) return alphabet[0];
  var arr = [];
  var base = alphabet.length;

  while(num) {
    rem = num % base;
    num = (num - rem)/base;
    arr.Push(alphabet.substring(rem,rem+1));
  }

  return arr.reverse().join('');
}

console.log(base62_encode(2390687438976, "123456789ABCDEFGHIJKLMNPQRSTUVWXYZ"));
2
Stephen

zbase62モジュールは pypi からダウンロードできます

例えば

>>> import zbase62
>>> zbase62.b2a("abcd")
'1mZPsa'
2
ghostdog74

次のスニペットが役立つことを願っています。

def num2sym(num, sym, join_symbol=''):
    if num == 0:
        return sym[0]
    if num < 0 or type(num) not in (int, long):
        raise ValueError('num must be positive integer')

    l = len(sym)  # target number base
    r = []
    div = num
    while div != 0: # base conversion
        div, mod = divmod(div, l)
        r.append(sym[mod])

    return join_symbol.join([x for x in reversed(r)])

あなたのケースの使用法:

number = 367891
alphabet = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
print num2sym(number, alphabet)  # will print '1xHJ'

明らかに、より少ないまたはより多い数の記号で構成される別のアルファベットを指定することができ、それはあなたの数をより少ないまたはより大きな数ベースに変換します。たとえば、アルファベットとして「01」を指定すると、入力番号を表す文字列がバイナリとして出力されます。

最初にアルファベットをシャッフルして、数字を一意に表現することができます。 URL短縮サービスを作成している場合に役立ちます。

2

個人的には、主に混乱するキャラクターを取り除くことで、Baishampayanのソリューションが気に入っています。

完全性とパフォーマンス向上のためのソリューションについては、 この投稿 は、Python base64モジュールを使用する方法を示しています。

1
Van Gale

これのためにpythonライブラリがあります。

このためのpipパッケージの作成に取り組んでいます。

Bases.pyを使用することをお勧めします https://github.com/kamijoutouma/bases.py bases.jsに触発された

from bases import Bases
bases = Bases()

bases.toBase16(200)                // => 'c8'
bases.toBase(200, 16)              // => 'c8'
bases.toBase62(99999)              // => 'q0T'
bases.toBase(200, 62)              // => 'q0T'
bases.toAlphabet(300, 'aAbBcC')    // => 'Abba'

bases.fromBase16('c8')               // => 200
bases.fromBase('c8', 16)             // => 200
bases.fromBase62('q0T')              // => 99999
bases.fromBase('q0T', 62)            // => 99999
bases.fromAlphabet('Abba', 'aAbBcC') // => 300

https://github.com/kamijoutouma/bases.py#known-basesalphabets を参照して、使用可能なベースを確認してください

1
Belldandu
BASE_LIST = Tuple("23456789ABCDEFGHJKLMNOPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz")
BASE_DICT = dict((c, v) for v, c in enumerate(BASE_LIST))
BASE_LEN = len(BASE_LIST)

def Nice_decode(str):
    num = 0
    for char in str[::-1]:
        num = num * BASE_LEN + BASE_DICT[char]
    return num

def Nice_encode(num):
    if not num:
        return BASE_LIST[0]

    encoding = ""
    while num:
        num, rem = divmod(num, BASE_LEN)
        encoding += BASE_LIST[rem]
    return encoding
1
paulkav1

これを行うための再帰的かつ反復的な方法を次に示します。反復処理は、実行回数に応じて少し速くなります。

def base62_encode_r(dec):
    s = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
    return s[dec] if dec < 62 else base62_encode_r(dec / 62) + s[dec % 62]
print base62_encode_r(2347878234)

def base62_encode_i(dec):
    s = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
    ret = ''
    while dec > 0:
        ret = s[dec % 62] + ret
        dec /= 62
    return ret
print base62_encode_i(2347878234)

def base62_decode_r(b62):
    s = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
    if len(b62) == 1:
        return s.index(b62)
    x = base62_decode_r(b62[:-1]) * 62 + s.index(b62[-1:]) % 62
    return x
print base62_decode_r("2yTsnM")

def base62_decode_i(b62):
    s = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
    ret = 0
    for i in xrange(len(b62)-1,-1,-1):
        ret = ret + s.index(b62[i]) * (62**(len(b62)-i-1))
    return ret
print base62_decode_i("2yTsnM")

if __== '__main__':
    import timeit
    print(timeit.timeit(stmt="base62_encode_r(2347878234)", setup="from __main__ import base62_encode_r", number=100000))
    print(timeit.timeit(stmt="base62_encode_i(2347878234)", setup="from __main__ import base62_encode_i", number=100000))
    print(timeit.timeit(stmt="base62_decode_r('2yTsnM')", setup="from __main__ import base62_decode_r", number=100000))
    print(timeit.timeit(stmt="base62_decode_i('2yTsnM')", setup="from __main__ import base62_decode_i", number=100000))

0.270266867033
0.260915645986
0.344734796766
0.311662500262
1
wenzul

私はしばらく前にこれを書いたが、それはかなりうまくいった(ネガとすべてが含まれている)

def code(number,base):
    try:
        int(number),int(base)
    except ValueError:
        raise ValueError('code(number,base): number and base must be in base10')
    else:
        number,base = int(number),int(base)
    if base < 2:
        base = 2
    if base > 62:
        base = 62
    numbers = [0,1,2,3,4,5,6,7,8,9,"a","b","c","d","e","f","g","h","i","j",
               "k","l","m","n","o","p","q","r","s","t","u","v","w","x","y",
               "z","A","B","C","D","E","F","G","H","I","J","K","L","M","N",
               "O","P","Q","R","S","T","U","V","W","X","Y","Z"]
    final = ""
    loc = 0
    if number < 0:
        final = "-"
        number = abs(number)
    while base**loc <= number:
        loc = loc + 1
    for x in range(loc-1,-1,-1):
        for y in range(base-1,-1,-1):
            if y*(base**x) <= number:
                final = "{}{}".format(final,numbers[y])
                number = number - y*(base**x)
                break
    return final

def decode(number,base):
    try:
        int(base)
    except ValueError:
        raise ValueError('decode(value,base): base must be in base10')
    else:
        base = int(base)
    number = str(number)
    if base < 2:
        base = 2
    if base > 62:
        base = 62
    numbers = ["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f",
               "g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v",
               "w","x","y","z","A","B","C","D","E","F","G","H","I","J","K","L",
               "M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"]
    final = 0
    if number.startswith("-"):
        neg = True
        number = list(number)
        del(number[0])
        temp = number
        number = ""
        for x in temp:
            number = "{}{}".format(number,x)
    else:
        neg = False
    loc = len(number)-1
    number = str(number)
    for x in number:
        if numbers.index(x) > base:
            raise ValueError('{} is out of base{} range'.format(x,str(base)))
        final = final+(numbers.index(x)*(base**loc))
        loc = loc - 1
    if neg:
        return -final
    else:
        return final

すべての長さについてすみません

1
Thropian

申し訳ありませんが、ここで図書館のお手伝いをすることはできません。 base64を使用し、可能であれば追加の文字を選択に追加することをお勧めします!

その後、base64モジュールを使用できます。

これが本当に可能な場合、実際には不可能です。

この方法で自分で行うことができます(これは擬似コードです):

base62vals = []
myBase = 62
while num > 0:
   reminder = num % myBase
   num = num / myBase
   base62vals.insert(0, reminder)
0
Juergen

単純な再帰

"""
This module contains functions to transform a number to string and vice-versa
"""
BASE = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
LEN_BASE = len(BASE)


def encode(num):
    """
    This function encodes the given number into alpha numeric string
    """

    if num < LEN_BASE:
        return BASE[num]

    return BASE[num % LEN_BASE] + encode(num//LEN_BASE)


def decode_recursive(string, index):
    """
    recursive util function for decode
    """

    if not string or index >= len(string):
        return 0

    return (BASE.index(string[index]) * LEN_BASE ** index) + decode_recursive(string, index + 1)


def decode(string):
    """
    This function decodes given string to number
    """

    return decode_recursive(string, 0)

0