преобразование десятичного числа в любое другое основание (2 & lt; = base & lt; = 36) в python [дубликат]

Если вам нужно отслеживать использование вашей памяти во время выполнения, пакет java.lang.management предлагает MBeans, который может использоваться для мониторинга пулов памяти в вашей виртуальной машине (например, пространство с эденом, поколение и т. д.), а также сбор мусора поведение.

Свободное пространство кучи, указанное этими MBeans, будет сильно отличаться в зависимости от поведения GC, особенно если ваше приложение генерирует много объектов, которые позже будут GC-ed. Один из возможных подходов - отслеживать свободное пространство кучи после каждого полного GC, которое вы можете использовать, чтобы принять решение об освобождении памяти от сохраняющихся объектов.

В конечном счете, ваш лучший выбор - ограничить вы сохраняете память, насколько это возможно, пока производительность остается приемлемой. Как отмечалось в предыдущем комментарии, память всегда ограничена, но ваше приложение должно иметь стратегию борьбы с исчерпанием памяти.

66
задан martineau 16 June 2016 в 19:20
поделиться

18 ответов

Я написал это некоторое время назад, и он работает очень хорошо (отрицательные и все включены)

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

извините за длину всего этого

127
ответ дан martineau 17 August 2018 в 21:28
поделиться
  • 1
    +1: Ницца! Это можно расширить с помощью более удобных для URL символов, чтобы, возможно, сохранить один символ здесь и там. Символы, которые я знаю, безопасны: $-_.+!*'(),;/?:@&= Возможно, вы также можете использовать некоторые другие символы, например []~ и т. Д. – Blixt 13 July 2009 в 15:32
  • 2
    base62_encode (-1) :) – Wojciech Bederski 13 July 2009 в 15:42
  • 3
    Именование ошибки: это не база 62, так как алфавит настраивается. – unwind 28 September 2009 в 15:24
  • 4
    Для декодирования лучше привыкнуть не вычислять мощности (экономит время, короче писать, но, что более важно, избегает ошибок «один за другим»), таким образом: num = 0; для символа в строке: num = num * base + alphabet.index (char) – ShreevatsaR 28 September 2009 в 15:31
  • 5
    @ShreevatsaR: любая конкретная причина использования str.index () вместо поиска в словаре? Смотрите мой ответ ... – John Machin 6 October 2009 в 00:47
127
ответ дан martineau 6 September 2018 в 13:46
поделиться
133
ответ дан martineau 29 October 2018 в 20:11
поделиться

Теперь для этого существует библиотека python.

Я работаю над созданием пакета pip для этого.

Я рекомендую использовать мои базы.py https : //github.com/kamijoutouma/bases.py , который был вдохновлен base.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-basicalphabets , для каких базисных функций

1
ответ дан Belldandu 17 August 2018 в 21:28
поделиться

Я как-то написал сценарий для этого, я думаю, это довольно элегантно:)

import string
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)
40
ответ дан Blender 17 August 2018 в 21:28
поделиться
  • 1
    Это здорово, спасибо. Мне нравится короткая :) – mikl 2 April 2010 в 16:39
  • 2
    Эта версия значительно быстрее, чем принятое решение от Baishampayan. Я еще больше оптимизировал вычисление длины вне функции. Результаты тестирования (100 000 итераций): версия-WoLpH: .403 .399 .399 .398 .398 | версия-Байшампаян: 1,783 1,785 1,782 1,788 1,784. Эта версия примерно в 4 раза быстрее. – Jordan 28 April 2011 в 14:46
  • 3
    если использовать reversed(string) быстрее, чем нарезка string[::-1] в функции base_decode. – ENDOH takanao 25 January 2014 в 05:18
  • 4
    Мне пришлось долго находить этот вопрос. Никогда не знал, что это называется преобразованием base62. Хороший ответ. – user 5 February 2016 в 10:49

вы можете загрузить модуль zbase62 из pypi

, например

>>> import zbase62
>>> zbase62.b2a("abcd")
'1mZPsa'
2
ответ дан ghostdog74 17 August 2018 в 21:28
поделиться
  • 1
    Да, я смотрел на это раньше, но он преобразует строки, а не цифры :) – mikl 13 July 2009 в 16:11

Если вы используете фреймворк django, вы можете использовать модуль django.utils.baseconv.

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

В дополнение к base62 baseconv также определил base2 / base16 / base36 / base56 / base64.

1
ответ дан heronotears 17 August 2018 в 21:28
поделиться

Следующий создатель декодера работает с любой разумной базой, имеет гораздо более аккуратный цикл и дает явное сообщение об ошибке, когда он встречает недопустимый символ.

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 __name__ == "__main__":
    func = base_n_decoder('0123456789abcdef')
    for test in ('0', 'f', '2020', 'ffff', 'abqdef'):
        print test
        print func(test)
8
ответ дан John Machin 17 August 2018 в 21:28
поделиться
  • 1
    Хотя я, вероятно, никогда не использовал бы это, я тоже дал вам большие пальцы для творчества. Этот код рассмешил меня. :) – Sepero 10 January 2013 в 15:07
  • 2
    @Sepero: Что смешно? Это серьезное прочное программное обеспечение для промышленной прочности. Никакой Микки-Маус не реверсируется с помощью оператора ** в цикле. – John Machin 15 January 2013 в 13:32
  • 3
    Успокойте себя другом. Ты прав. Я пропустил истинную доброту вашей внутренней петли из-за того, что она была похоронена в вещах, которые не связаны с вопросом (обертка, проверка ошибок, модульное тестирование). – Sepero 15 January 2013 в 20:26
  • 4
    Выглядит хорошо, но разве вы не забыли «промышленную силу»? кодировщик, который принимает целое число плюс алфавит для создания строки? – martineau 17 January 2013 в 04:27
  • 5
    Было ли q в последнем значении преднамеренным показать поднятие ValueError? – Thomas Vander Stichele 14 August 2014 в 15:15

Извините, я не могу помочь вам с библиотекой здесь. Я предпочел бы использовать base64 и просто добавлять дополнительные символы к вашему выбору - если это возможно!

Тогда вы можете использовать модуль base64.

Если это действительно, действительно невозможно:

Вы можете сделать это самостоятельно (это псевдокод):

base62vals = []
myBase = 62
while num > 0:
   reminder = num % myBase
   num = num / myBase
   base62vals.insert(0, reminder)
0
ответ дан Juergen 17 August 2018 в 21:28
поделиться
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 17 August 2018 в 21:28
поделиться
  • 1
    Это фиксирует имя BASE_LIST, а также отменяет строку при декодировании, которая была опущена в отличном ответе Сперо – paulkav1 29 March 2013 в 02:51
  • 2
    FYI в строке ввода отсутствует несколько символов / чисел. – mafrosis 27 February 2017 в 09:37

Если вы ищете максимальную эффективность (например, 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

Закодировано и декодировано 1 миллион номеров менее чем за 2,5 секунды. (2,2 ГГц i7-2670QM)

7
ответ дан Sepero 17 August 2018 в 21:28
поделиться
  • 1
    Вначале не обязательно нужно tuple() вокруг BASE_ALPH. В Python каждая строка является итерируемой. Эта функция, конечно, используется enumerate(). Так что код становится даже более скудным :) – Luis Nell 18 April 2013 в 17:05
  • 2
    Эй, origiNell, вы правы, что кортеж () не нужен, но в моей системе он заставляет код работать примерно на 20% быстрее. Попробуйте проверить его без кортежа () и посмотрите, что лучше всего подходит для вас. Приветствия :) – Sepero 24 April 2013 в 08:20
  • 3
    Интересный момент. Делает полный смысл, поскольку кортежи более легкие, чем строки. Спасибо за просветление :)! – Luis Nell 25 April 2013 в 09:44
  • 4
    @Sepero Я улучшил вашу версию с точки зрения форматирования, именования, тестирования и функциональности (поддерживаются отрицательные числа): pastebin.com/4uket7iu (вы можете обновить свой ответ этим) – Joschua 12 August 2014 в 16:15
  • 5
    @SMGreenfield Можете ли вы привести несколько примеров, которые не работают? – Joschua 27 May 2015 в 08:29

У меня есть библиотека Python для выполнения именно этого здесь: http://www.djangosnippets.org/snippets/1431/

3
ответ дан Simon Willison 17 August 2018 в 21:28
поделиться

Если вам нужно только создать короткий идентификатор (поскольку вы упомянете укороченные URL-адреса), а не кодировать / декодировать что-то, этот модуль может помочь:

https://github.com/ стохастической технологии / shortuuid /

3
ответ дан Stavros Korokithakis 17 August 2018 в 21:28
поделиться
  • 1
    Я не уверен, что подходит для коротких URL. UUID, как правило, очень большое число, поэтому даже base57, кодирующий его, как он, очень длинный для короткого URL. – mikl 11 January 2011 в 15:55
  • 2
    Вы можете просто сократить столько, сколько хотите, столкновений все равно маловероятно, поскольку это чисто случайный, но больше не будет уникальным идентификатором. – Stavros Korokithakis 22 January 2011 в 00:09

Я получил большую пользу от других сообщений здесь. Мне сначала понадобился код python для проекта Django, но с тех пор я перешел на node.js, поэтому здесь представлена ​​ версия javascript кода (часть кодирования), которую предоставил 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 17 August 2018 в 21:28
поделиться

Лично мне нравится решение от Baishampayan, в основном из-за удаления запутанных символов.

Для полноты и решения с лучшей производительностью этот пост показывает способ использования Модуль base64 для Python.

1
ответ дан Van Gale 17 August 2018 в 21:28
поделиться
  • 1
    Как упоминалось в моем комментарии к Williham Totland, Pythons base64 субоптимален для кодирования чисел, поскольку он оптимизирован для строк. – mikl 2 April 2010 в 16:37

Я надеюсь, что следующий фрагмент может помочь.

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
ответ дан Vladimir Ignatyev 17 August 2018 в 21:28
поделиться
  • 1
    Неплохо. Вы можете использовать if num < 0 or type(num) not in (int, long):. – martineau 25 June 2013 в 16:28
  • 2
    спасибо, просто зафиксировал его – Vladimir Ignatyev 25 June 2013 в 17:52
  • 3
    Это лучше, но это немного сложнее, потому что long не существует в Py 3.x - поэтому вы можете использовать этот ответ . – martineau 25 June 2013 в 19:25
  • 4
    Или используйте мою собственную переносимую версию: isinstance(x, (type(1), type(2**32))). – martineau 25 June 2013 в 20:35

Вот рекурсивный и итеративный способ сделать это. Итеративный немного быстрее в зависимости от количества выполнения.

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 __name__ == '__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 17 August 2018 в 21:28
поделиться
  • 1
    Мне очень понравился ваш рекурсивный подход. Моя дочь, которая принимала AP Comp Sci, вычислила это же решение для меня, чтобы реализовать «base25», (используя «ABCDEFHJKMNPQRTUVWXY34789») в C ++. Я пошел преобразовывать его в Python и быть полным новичком с этим языком, ударил несколько камней преткновения - которые вы элегантно решили в одной строке кода! Вы даже избегаете распространенной проблемы с 0, переводящей пустую строку в алфавиты, которые не начинаются с 0-9. Отличная работа! (Мне не нужны отрицательные числа, но ваш подход был настолько хорош, что было бы неплохо добавить это для будущих браузеров) – SMGreenfield 26 May 2015 в 03:58
  • 2
    @SMGreenfield Большое спасибо за ваши отзывы. – wenzul 26 May 2015 в 10:29

Вероятно, вы хотите base64, а не base62. Существует версия для совместимости с URL-адресами, поэтому дополнительные два символа-заполнителя не должны быть проблемой.

Процесс довольно прост; что base64 представляет 6 бит, а обычный байт представляет 8. Назначьте значение от 000000 до 111111 каждому из 64 выбранных символов и поместите 4 значения вместе, чтобы они соответствовали набору из 3 базовых 256 байтов. Повторите для каждого набора из 3 байтов, добавив в конец ваш выбор символа заполнения (обычно полезно 0).

4
ответ дан Williham Totland 17 August 2018 в 21:28
поделиться
  • 1
    Стандартные методы кодирования base64 на базе Python на самом деле не подходят для коротких URL-адресов, так как они оптимизированы для кодирования байтов (т. Е. Строк / букв) и будут давать более длинные выходы, чем просто базовое смещение численного значения. – mikl 2 April 2010 в 16:34
  • 2
    @mikl Конечно, модуль base64 Python может не подходить для генерации коротких URL-адресов, но все методы кодирования Python действительно работают с числовыми последовательностями base-256. байты действительно закодированы «256 строк». Python 2.x рассматривает строки как последовательность байтов, тогда как Python 3.x (что делает правильную вещь) обрабатывает строки как Unicode. Таким образом, b'foobar '- это всего лишь фантастический способ записи [102, 111, 111, 98, 97, 114] или [0x66,0x6f, 0x6f, 0x62,0x61,0x72] или b' \ x66 \ x6f \ x6f \ x62 \ x61 \ x72 ', что неудивительно - это представление base-256. Байты не являются строками или буквами. Байты - байты. знак равно – yesudeep 9 August 2011 в 15:19
  • 3
    @yesudeep: Итак, байты - это байты ... и что именно ваша точка? – martineau 17 January 2013 в 03:29
Другие вопросы по тегам:

Похожие вопросы: