python允许使用范围[2,36]中的任何基数使用:
将字符串转换为整数int(string,base)
我正在寻找一个优雅的反函数,它接受一个整数和一个基数并返回一个字符串
例如
>>> str_base(224,15)
'ee'
我有以下解决方案:
def digit_to_char(digit):
if digit < 10: return chr(ord('0') + digit)
else: return chr(ord('a') + digit - 10)
def str_base(number,base):
if number < 0:
return '-' + str_base(-number,base)
else:
(d,m) = divmod(number,base)
if d:
return str_base(d,base) + digit_to_char(m)
else:
return digit_to_char(m)
注意:digit_to_char()适用于基数&lt; = 169,任意使用ascii字符后'z'作为36以上碱基的数字
是否有python内置函数,库函数或更优雅的int函数(字符串,基数)?
答案 0 :(得分:30)
也许这不应该是一个答案,但它可能对某些人有所帮助:内置的format
函数确实在几个基础上将数字转换为字符串:
>>> format(255, 'b') # base 2
'11111111'
>>> format(255, 'd') # base 10
'255'
>>> format(255, 'o') # base 8
'377'
>>> format(255, 'x') # base 16
'ff'
答案 1 :(得分:18)
如果您使用Numpy,则有numpy.base_repr
。
您可以阅读numpy/core/numeric.py
下的代码。短而优雅
答案 2 :(得分:11)
This thread有一些示例实现。
实际上我认为你的解决方案看起来相当不错,它甚至是递归的,这在某种程度上令人满意。
我仍然会简化它以删除else
,但这可能是个人风格的事情。我认为if foo: return
非常清楚,并且在它之后不需要else
来表明它是一个单独的分支。
def digit_to_char(digit):
if digit < 10:
return str(digit)
return chr(ord('a') + digit - 10)
def str_base(number,base):
if number < 0:
return '-' + str_base(-number, base)
(d, m) = divmod(number, base)
if d > 0:
return str_base(d, base) + digit_to_char(m)
return digit_to_char(m)
我简化了digit_to_char()
中的0-9案例,我认为str()
比chr(ord())
构造更清晰。为了最大化>= 10
情况下的对称性,可以考虑ord()
,但我没有打扰,因为它会增加一条线,简洁感更好。 :)
答案 3 :(得分:6)
以上答案非常好。它帮助我制作了一个我必须在C中实现的算法的原型。
我想提出一点改变(我用过)将十进制转换为符号空间的基础
我也忽略了否定价值只是为了简短和数学不正确的事实 - &GT;模块化算术的其他规则 - &GT;其他数学如果你使用二进制,八进制或十六进制 - &gt; diff in unsigned&amp;签名值
def str_base(number, base):
(d,m) = divmod(number,len(base))
if d > 0:
return str_base(d,base)+base[m]
return base[m]
导致以下输出
>>> str_base(13,'01')
'1101'
>>> str_base(255,'01')
'11111111'
>>> str_base(255,'01234567')
'377'
>>> str_base(255,'0123456789')
'255'
>>> str_base(255,'0123456789abcdef')
'ff'
>>> str_base(1399871903,'_helowrd')
'hello_world'
如果你想使用propper零符号填充,你可以使用
symbol_space = 'abcdest'
>>> str_base(734,symbol_space).rjust(0,symbol_space[0])
'catt'
>>> str_base(734,symbol_space).rjust(6,symbol_space[0])
'aacatt'
答案 4 :(得分:4)
回顾一下。
def int2str(num, base=16, sbl=None):
if not sbl:
sbl = '0123456789abcdefghijklmnopqrstuvwxyz'
if len(sbl) < 2:
raise ValueError, 'size of symbols should be >= 2'
if base < 2 or base > len(sbl):
raise ValueError, 'base must be in range 2-%d' % (len(sbl))
neg = False
if num < 0:
neg = True
num = -num
num, rem = divmod(num, base)
ret = ''
while num:
ret = sbl[rem] + ret
num, rem = divmod(num, base)
ret = ('-' if neg else '') + sbl[rem] + ret
return ret
答案 5 :(得分:2)
digit_to_char
可以像这样实现:
def digit_to_char(digit):
return (string.digits + string.lowercase)[digit]
答案 6 :(得分:2)
我曾经以同样的目标编写了自己的函数,但现在却非常复杂。
from math import log, ceil, floor
from collections import deque
from itertools import repeat
from string import uppercase, digits
import re
__alphanumerals = (digits + uppercase)
class InvalidBaseError(ValueError): pass
class FloatConvertError(ValueError): pass
class IncorrectBaseError(ValueError): pass
def getbase(number, base=2, frombase = 10):
if not frombase == 10:
number = getvalue(number, frombase)
#getvalue is also a personal function to replicate int(number, base)
if 1 >= base or base >= len(__alphanumerals) or not floor(base) == base:
raise InvalidBaseError("Invalid value: {} entered as base to convert
to. \n{}".format(base,
"Assert that the base to convert to is a decimal integer."))
if isinstance(number, str):
try:
number = atof(number)
except ValueError:
#The first check of whether the base is 10 would have already corrected the number
raise IncorrectBaseError("Incorrect base passed as base of number -> number: {} base: {}".format(number, frombase))
#^ v was supporting float numbers incase number was the return of another operation
if number > floor(number):
raise FloatConvertError("The number to be converted must not be a float. {}".format(number))
isNegative = False
if number < 0:
isNegative = True
number = abs(number)
logarithm = log(number, base) if number else 0 #get around number being zero easily
ceiling = int(logarithm) + 1
structure = deque(repeat(0, ceiling), maxlen = ceiling)
while number:
if number >= (base ** int(logarithm)):
acceptable_digit = int(number / (base ** floor(logarithm)))
structure.append(acceptable_digit if acceptable_digit < 10 else __alphanumerals[acceptable_digit])
number -= acceptable_digit * (base ** floor(logarithm))
else:
structure.append(0)
logarithm -= 1
while structure[0] == 0:
#the result needs trailing zeros
structure.rotate(-1)
return ("-" if isNegative and number else "") + reduce(lambda a, b: a + b, map(lambda a: str(a), structure))
我认为strbase函数应该只支持base&gt; = 2和&lt; = 36以防止与python中的其他工具冲突,例如int。 此外,我认为只应使用一个字母大小写字母,最好再大写,以防止与其他函数如int冲突,因为它会将“a”和“A”都视为10。
from string import uppercase
dig_to_chr = lambda num: str(num) if num < 10 else uppercase[num - 10]
def strbase(number, base):
if not 2 <= base <= 36:
raise ValueError("Base to convert to must be >= 2 and <= 36")
if number < 0:
return "-" + strbase(-number, base)
d, m = divmod(number, base)
if d:
return strbase(d, base) + dig_to_chr(m)
return dig_to_chr(m)
答案 7 :(得分:0)
这是我的解决方案:
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...
。 “使命”是找到所有的。
对于每个N=1,2,3...
,代码将aN*base**N
通过“mouduling”隔离为b b=base**(N+1)
将所有大于N的切片隔离,并切割所有a的序列为每当函数被当前aN*base**N
调用时,通过减小a来小于N.
Base%(base-1)==1
返回base**p%(base-1)==1
时,{p> q*base^p%(base-1)==q
q=base-1
因此0
只有一个例外。
要解决这个问题,如果它返回0
,该函数将从头开始检查0
。
在这个样本中,只有一个乘法(而不是除法)和一些模数实例需要相对较少的时间。
答案 8 :(得分:0)
看起来这可能是我发光的时候了。信不信由你,以下是我近三年前写的一些移植和修改的Scratch代码,看看我能用多快的速度从denary转换为十六进制。
简单地说,它首先采用整数,基数和可选的附带数字串,然后计算从最低有效数开始的转换整数的每个数字。
def int2base(num, base, abc="0123456789abcdefghijklmnopqrstuvwxyz"):
if num < 0:
return '-' + int2base(-num, base, abc)
else:
output = abc[num % base] # rightmost digit
while num >= base:
num //= base # move to next digit to the left
output = abc[num % base] + output # this digit
return output
在我自己的PC上,此代码能够使用输入范围0-9999和基数36完成1000万次迭代,始终低于5秒。 使用相同的测试,我发现至少比其他任何答案快4秒。
>>> timeit.timeit(lambda: [int2base(n, 36) for n in range(10000)], number=1000)
4.883068453882515
答案 9 :(得分:0)
numpy.base_repr
是一个很好的解决方案,但是,在某些情况下,我们希望使用带有前导零的固定长度字符串。
def base_repr(x: int, base: int, length: int):
from numpy import base_repr
from math import log, ceil
s = base_repr(x, base, length - ceil(log(x, base)))
return s
答案 10 :(得分:0)
这是一个递归函数:
def encode(nIn, nBase):
n = nIn // nBase
s = '0123456789abcdefghijklmnopqrstuvwxyz'[nIn % nBase]
return encode(n, nBase) + s if n > 0 else s
n = 1577858399
s = encode(n, 36)
print(s == 'q3ezbz')