web-dev-qa-db-ja.com

任意のベースの整数を文字列に変換する方法は?

Pythonでは、指定されたベースの文字列から整数を簡単に作成できます。

int(str, base). 

私は逆を実行したい:整数からの文字列の作成、つまり、次のような関数int2base(num, base)が必要です:

int(int2base(x, b), b) == x

関数名/引数の順序は重要ではありません。

int()が受け入れる任意の数xおよびベースbに対して。

これは簡単に記述できる関数です。実際、この質問で説明するよりも簡単です。しかし、私は何かを見逃しているに違いないと感じています。

関数binocthexについては知っていますが、いくつかの理由で使用できません。

  • これらの関数は古いバージョンのPythonでは利用できません。(2.2)

  • 異なるベースに対して同じ方法で呼び出すことができる一般的なソリューションが必要です

  • 2、8、16以外のベースを許可したい

関連する

177
Mark Borgerding

Pythonの古いバージョンとの互換性が必要な場合は、 gmpy (高速で完全に一般的なintから文字列への変換関数を含み、そのような古いバージョン用にビルドできます)のいずれかを使用できます最近のリリースは、由緒あるPythonおよびGMPリリースではテストされていないため、古いリリースを試してみる必要があるかもしれませんが、速度は遅くなりますが、利便性はPythonコード-例えば、最も単純な例:

import string
digs = string.digits + string.ascii_letters


def int2base(x, base):
    if x < 0:
        sign = -1
    Elif x == 0:
        return digs[0]
    else:
        sign = 1

    x *= sign
    digits = []

    while x:
        digits.append(digs[int(x % base)])
        x = int(x / base)

    if sign < 0:
        digits.append('-')

    digits.reverse()

    return ''.join(digits)
84
Alex Martelli
def baseN(num,b,numerals="0123456789abcdefghijklmnopqrstuvwxyz"):
    return ((num == 0) and numerals[0]) or (baseN(num // b, b, numerals).lstrip(numerals[0]) + numerals[num % b])

参照: http://code.activestate.com/recipes/65212/

これにより、

RuntimeError: maximum recursion depth exceeded in cmp

非常に大きな整数の場合。

87
jellyfishtree

驚くべきことに、人々は小さなベース(英語のアルファベットの長さよりも小さい)に変換するソリューションのみを提供していました。 2から無限大までの任意のベースに変換するソリューションを提供する試みはありませんでした。

だからここに超簡単な解決策があります:

def numberToBase(n, b):
    if n == 0:
        return [0]
    digits = []
    while n:
        digits.append(int(n % b))
        n //= b
    return digits[::-1]

そのため、超巨大な数値をベース577に変換する必要がある場合、

numberToBase(67854 ** 15 - 102, 577)、正しい解決策を提供します:[4, 473, 131, 96, 431, 285, 524, 486, 28, 23, 16, 82, 292, 538, 149, 25, 41, 483, 100, 517, 131, 28, 0, 435, 197, 264, 455]

後で必要なベースに変換できます

86
Salvador Dali
"{0:b}".format(100) # bin: 1100100
"{0:x}".format(100) # hex: 64
"{0:o}".format(100) # oct: 144
70
Rost

素晴らしい答えです!私の質問に対する答えは「いいえ」だったと思います。明らかな解決策を見逃していませんでした。これが、答えで表現された良いアイデアを凝縮する、私が使用する関数です。

  • 呼び出し元が提供する文字のマッピングを許可します(base64エンコードを許可します)
  • 負とゼロをチェックします
  • 複素数を文字列のタプルにマッピングします

def int2base(x,b,alphabet='0123456789abcdefghijklmnopqrstuvwxyz'):
    'convert an integer to its string representation in a given base'
    if b<2 or b>len(alphabet):
        if b==64: # assume base64 rather than raise error
            alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
        else:
            raise AssertionError("int2base base out of range")
    if isinstance(x,complex): # return a Tuple
        return ( int2base(x.real,b,alphabet) , int2base(x.imag,b,alphabet) )
    if x<=0:
        if x==0:
            return alphabet[0]
        else:
            return  '-' + int2base(-x,b,alphabet)
    # else x is non-negative real
    rets=''
    while x>0:
        x,idx = divmod(x,b)
        rets = alphabet[idx] + rets
    return rets


20
Mark Borgerding

Pythonには、任意の基数で整数を出力するための組み込み関数がありません。必要に応じて、独自に記述する必要があります。

15
Mike Graham

私のプロジェクトからbaseconv.pyを使用できます: https://github.com/semente/python-baseconv

サンプル使用法:

>>> from baseconv import BaseConverter
>>> base20 = BaseConverter('0123456789abcdefghij')
>>> base20.encode(1234)
'31e'
>>> base20.decode('31e')
'1234'
>>> base20.encode(-1234)
'-31e'
>>> base20.decode('-31e')
'-1234'
>>> base11 = BaseConverter('0123456789-', sign='$')
>>> base11.encode('$1234')
'$-22'
>>> base11.decode('$-22')
'$1234'

たとえば、baseconv.base2baseconv.base16baseconv.base64などのブルタンコンバーターがあります。

13
semente

再帰的

私はsimplify最も投票された答え に:

BS="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
def to_base(n, b): 
    return "0" if not n else to_base(n//b, b).lstrip("0") + BS[n%b]

非常に大きな整数と負の数のRuntimeError: maximum recursion depth exceeded in cmpについても同じアドバイスがあります。 (使用できます sys.setrecursionlimit(new_limit)

反復的

再帰問題を回避する

BS="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
def to_base(s, b):
    res = ""
    while s:
        res+=BS[s%b]
        s//= b
    return res[::-1] or "0"
6
M.M

http://code.activestate.com/recipes/65212/

def base10toN(num,n):
    """Change a  to a base-n number.
    Up to base-36 is supported without special notation."""
    num_rep={10:'a',
         11:'b',
         12:'c',
         13:'d',
         14:'e',
         15:'f',
         16:'g',
         17:'h',
         18:'i',
         19:'j',
         20:'k',
         21:'l',
         22:'m',
         23:'n',
         24:'o',
         25:'p',
         26:'q',
         27:'r',
         28:'s',
         29:'t',
         30:'u',
         31:'v',
         32:'w',
         33:'x',
         34:'y',
         35:'z'}
    new_num_string=''
    current=num
    while current!=0:
        remainder=current%n
        if 36>remainder>9:
            remainder_string=num_rep[remainder]
        Elif remainder>=36:
            remainder_string='('+str(remainder)+')'
        else:
            remainder_string=str(remainder)
        new_num_string=remainder_string+new_num_string
        current=current/n
    return new_num_string

同じリンクからの別のものはここにあります

def baseconvert(n, base):
    """convert positive decimal integer n to equivalent in another base (2-36)"""

    digits = "0123456789abcdefghijklmnopqrstuvwxyz"

    try:
        n = int(n)
        base = int(base)
    except:
        return ""

    if n < 0 or base < 2 or base > 36:
        return ""

    s = ""
    while 1:
        r = n % base
        s = digits[r] + s
        n = n / base
        if n == 0:
            break

    return s
4
John La Rooy

このために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 使用可能なベースについて

編集:pipリンク https://pypi.python.org/pypi/bases.py/0.2.2

4
Belldandu
def base(decimal ,base) :
    list = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    other_base = ""
    while decimal != 0 :
        other_base = list[decimal % base] + other_base
        decimal    = decimal / base
    if other_base == "":
        other_base = "0"
    return other_base

print base(31 ,16)

出力:

「1F」

3
mukundan

>>> numpy.base_repr(10, base=3) '101'

3
V. Ayrat
num = input("number")
power = 0
num = int(num)
while num > 10:
    num = num / 10
    power += 1

print(str(round(num, 2)) + "^" + str(power))
1
Casey Howard
>>> import string
>>> def int2base(integer, base):
        if not integer: return '0'
        sign = 1 if integer > 0 else -1
        alphanum = string.digits + string.ascii_lowercase
        nums = alphanum[:base]
        res = ''
        integer *= sign
        while integer:
                integer, mod = divmod(integer, base)
                res += nums[mod]
        return ('' if sign == 1 else '-') + res[::-1]


>>> int2base(-15645, 23)
'-16d5'
>>> int2base(213, 21)
'a3'
1
SilentGhost
def int2base(a, base, numerals="0123456789abcdefghijklmnopqrstuvwxyz"):
    baseit = lambda a=a, b=base: (not a) and numerals[0]  or baseit(a-a%b,b*base)+numerals[a%b%(base-1) or (a%b) and (base-1)]
    return baseit()

説明

どのベースでも、すべての数値はa1+a2*base**2+a3*base**3...に等しくなります。「ミッション」はすべてのaを見つけることです。

EveryN=1,2,3...の場合、コードはb=base**(N+1)をbで「取り消す」ことでaN*base**Nを分離し、aをすべてNより大きくスライスし、aのすべてをスライスします。現在のaN*base**N

Base%(base-1)== 1 base ** p%(base-1)== 1の場合、q * base ^ p%(base-1)== qの場合、q = base-1の場合は例外が1つのみ0を返します。0を返す場合に修正するために、funcは最初から0をチェックしています。


利点

このサンプルでは、​​(除算ではなく)1回の乗算と、比較的短い時間で実行される一部のモジュールがあります。

1
Shu ba

興味のある人のための再帰的なソリューション。もちろん、これは負のバイナリ値では機能しません。 Two's Complementを実装する必要があります。

def generateBase36Alphabet():
    return ''.join([str(i) for i in range(10)]+[chr(i+65) for i in range(26)])

def generateAlphabet(base):
    return generateBase36Alphabet()[:base]

def intToStr(n, base, alphabet):
    def toStr(n, base, alphabet):
        return alphabet[n] if n < base else toStr(n//base,base,alphabet) + alphabet[n%base]
    return ('-' if n < 0 else '') + toStr(abs(n), base, alphabet)

print('{} -> {}'.format(-31, intToStr(-31, 16, generateAlphabet(16)))) # -31 -> -1F
1
Mr. Polywhirl

別の短いもの(そして理解しやすいimo):

def int_to_str(n, b, symbols='0123456789abcdefghijklmnopqrstuvwxyz'):
    return (int_to_str(n/b, b, symbols) if n >= b else "") + symbols[n%b]

そして、適切な例外処理により:

def int_to_str(n, b, symbols='0123456789abcdefghijklmnopqrstuvwxyz'):
    try:
        return (int_to_str(n/b, b) if n >= b else "") + symbols[n%b]
    except IndexError:
        raise ValueError(
            "The symbols provided are not enough to represent this number in "
            "this base")
0
Ariel

これは、符号付き整数とカスタム数字を処理する再帰バージョンです。

import string

def base_convert(x, base, digits=None):
    """Convert integer `x` from base 10 to base `base` using `digits` characters as digits.
    If `digits` is omitted, it will use decimal digits + lowercase letters + uppercase letters.
    """
    digits = digits or (string.digits + string.ascii_letters)
    assert 2 <= base <= len(digits), "Unsupported base: {}".format(base)
    if x == 0:
        return digits[0]
    sign = '-' if x < 0 else ''
    x = abs(x)
    first_digits = base_convert(x // base, base, digits).lstrip(digits[0])
    return sign + first_digits + digits[x % base]
0
Antoine Pinsard
def baseConverter(x, b):
    s = ""
    d = string.printable.upper()
    while x > 0:
        s += d[x%b]
        x = x / b
    return s[::-1]
0
gjivanya
def dec_to_radix(input, to_radix=2, power=None):
    if not isinstance(input, int):
        raise TypeError('Not an integer!')
    Elif power is None:
        power = 1

    if input == 0:
        return 0
    else:
        remainder = input % to_radix**power
        digit = str(int(remainder/to_radix**(power-1)))
        return int(str(dec_to_radix(input-remainder, to_radix, power+1)) + digit)

def radix_to_dec(input, from_radix):
    if not isinstance(input, int):
        raise TypeError('Not an integer!')
    return sum(int(digit)*(from_radix**power) for power, digit in enumerate(str(input)[::-1]))

def radix_to_radix(input, from_radix=10, to_radix=2, power=None):
    dec = radix_to_dec(input, from_radix)
    return dec_to_radix(dec, to_radix, power)
0
nameisnotphil

別のソリューションは、ベース2〜10で動作し、より高いベースの場合は変更が必要です。

def n2b(n, b):
    if n == 0:
        return 0
    d = []
    while n:
        d.append(int(n % b))
        n /= b
    return ''.join(map(str,d[::-1]))

例:

n2b(10,2) => '10100'
int(n2b(10,2),2) => 10
0
Stanislav

数字を表すための唯一の選択肢は文字列ではありません。整数のリストを使用して各桁の順序を表すことができます。これらは簡単に文字列に変換できます。

いずれの回答も、ベース<2を拒否しません。ほとんどの場合、非常に遅く実行されるか、非常に大きい数(56789 ** 43210など)のスタックオーバーフローでクラッシュします。このような障害を回避するには、次のようにすばやく減らします。

def n_to_base(n, b):
    if b < 2: raise # invalid base
    if abs(n) < b: return [n]
    ret = [y for d in n_to_base(n, b*b) for y in divmod(d, b)]
    return ret[1:] if ret[0] == 0 else ret # remove leading zeros

def base_to_n(v, b):
    h = len(v) // 2
    if h == 0: return v[0]
    return base_to_n(v[:-h], b) * (b**h) + base_to_n(v[-h:], b)

assert ''.join(['0123456789'[x] for x in n_to_base(56789**43210,10)])==str(56789**43210)

速度的には、n_to_baseは大きな数(私のマシンでは約0.3秒)でstrと同等ですが、hexと比較すると驚くかもしれません(私のマシンでは約0.3ms、または1000倍高速)。その理由は、大きな整数がベース256(バイト)でメモリに格納されるためです。各バイトは、単純に2文字の16進文字列に変換できます。この整列は、2の累乗であるベースに対してのみ発生します。そのため、2、8、および16(およびbase64、ascii、utf16、utf32)には特別なケースがあります。

10進数文字列の最後の桁を考慮してください。整数を形成するバイトシーケンスとどのように関連していますか? s[i]が最下位(リトルエンディアン)であるバイトs[0]にラベルを付けましょう。その場合、最後の桁はsum([s[i]*(256**i) % 10 for i in range(n)])です。さて、256 ** iが6 for i> 0(6 * 6 = 36)で終わるため、最後の桁が(s[0]*5 + sum(s)*6)%10になります。これから、最後の桁がすべてのバイトの合計に依存していることがわかります。この非ローカルプロパティは、10進数への変換を困難にするものです。

0
colski