英文:
Acessing unexported function `nat.string`
问题
我想将一个big.Int
转换为简单的base32格式。不是像base32
实现的RFC 4648标准base32格式,也不是zBase32或Crockford,我只想要每个字符5位的普通0-9A-V字符集。
我知道有base32
包,但它不能满足我的需求——它构建的结果是带有填充和其他我不想要的标准base32数字。当然,我可以使用它,然后去掉末尾的“=”字符,对剩下的部分进行修改,但这似乎是一个粗暴的解决方案。
有一个big.SetString(string, base)
可以解析字符串形式的base32数字,但没有相反的操作——这才是我真正想要的,类似于Java的BigInteger.toString(int base)
的big.GetString(base)
。
然而,有一个nat.string
正好满足我的需求。我如何获得对它的访问权限?
有没有办法我可以手动扩展big
来实现big.GetString(base)
,它简单地调用具有正确charset
的nat.string
?
有没有办法我可以访问big
使用的未导出的big.nat
,并调用nat.string
?
还有其他什么我可以做的吗?
附注:我也对使用nat.trailingZeroBits
感兴趣——我不得不自己编写它,因为我没有意识到这已经存在。
英文:
I want to convert a big.Int
to simple base32. Not the standard base32 stuff like the RFC 4648 implemented by base32
nor zBase32 nor Crockford I want just simple normal 5-bits per character 0-9A-V character set.
I am aware of the base32
package and it does not do what I want - it builds the result in a standard base 32 number with padding and stuff I don't want. Certainly I could use it and tear off the trailing "=" characters and hack what remains but that just seems like a brutal solution.
There is a big.SetString(string, base)
that can parse a base32 number in string form but there is no reverse - which is what I am really looking for, a big.GetString(base)
like the Java BigInteger.toString(int base)
.
There is, however, a nat.string
which does exactly what I want. How can I gain access to it?
Is there a way I could manually extend big
to implement big.GetString(base)
which trivially calls nat.string
with the correct charset
?
Is there a way I can reach into the unexported big.nat
which big
uses and call nat.string
?
Is there something else I can do?
P.S. I'd also be interested in using nat.trailingZeroBits
- I had to write my own because I didn't realise this was already done.
答案1
得分: 2
你无法访问未导出的函数。为了实现该功能,你需要重新编写nat.go
的至少一部分代码。其中一些函数看起来非常有用,所以值得考虑向golang-nuts
组发送一个功能请求,要求在未来的版本中将其中一些函数导出。
但是,你可以使用strconv.FormatInt()
来实现你的需求。
给定一个big.Int
类型的变量b
,你可以这样做:
strconv.FormatInt(b.Int64(), 32)
完整示例:
package main
import (
"fmt"
"math/big"
"strconv"
)
func main() {
i := 3286583923486565782 // 一个随机整数
b := big.NewInt(int64(i))
fmt.Println(strconv.FormatInt(b.Int64(), 32))
}
输出结果:
>>2r72al99uq9cm
英文:
You can't access unexported functions at all. You'd need to re-write at least some portion of nat.go
in order to achieve that functionality. Some of those functions look very useful, so it may be worth sending a feature request to the golang-nuts
group asking for some of them to be exported in a future release.
You can however use strconv.FormatInt()
to do what you require.
given a big.Int
b
you can do:
strconv.FormatInt(b.Int64(), 32)
Full example:
package main
import (
"fmt"
"math/big"
"strconv"
)
func main() {
i := 3286583923486565782 // Some random integer
b := big.NewInt(int64(i))
fmt.Println(strconv.FormatInt(b.Int64(), 32))
}
Produces:
>>2r72al99uq9cm
答案2
得分: 2
我不认为Go团队会在nat
中导出任何东西,因为那是big.Int
的实现细节。不过,他们可能会对从big.Int
导出一个ToBase
函数的请求持开放态度。
与此同时,这是一个经过轻度测试的简单进制转换器的代码:
func ToBase(x *big.Int, base int) string {
if x.Sign() == 0 {
return "0"
}
y := new(big.Int).Set(x)
b := big.NewInt(int64(base))
charset := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
out := make([]byte, 0, 16)
negative := false
if y.Sign() < 0 {
negative = true
y.Neg(y)
}
digit := new(big.Int)
for y.Sign() != 0 {
y.DivMod(y, b, digit)
out = append(out, charset[digit.Int64()])
}
if negative {
out = append(out, '-')
}
// Reverse out
for i, j := 0, len(out)-1; i < j; i, j = i+1, j-1 {
out[i], out[j] = out[j], out[i]
}
return string(out)
}
英文:
I don't think the go team will ever export anything in nat
as that is an implementation details for big.Int
. They may look kindly upon a request to export a ToBase
function though from big.Int
.
In the mean time here is a lightly tested naive base converter for you
func ToBase(x *big.Int, base int) string {
if x.Sign() == 0 {
return "0"
}
y := new(big.Int).Set(x)
b := big.NewInt(int64(base))
charset := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
out := make([]byte, 0, 16)
negative := false
if y.Sign() < 0 {
negative = true
y.Neg(y)
}
digit := new(big.Int)
for y.Sign() != 0 {
y.DivMod(y, b, digit)
out = append(out, charset[digit.Int64()])
}
if negative {
out = append(out, '-')
}
// Reverse out
for i, j := 0, len(out)-1; i < j; i, j = i+1, j-1 {
out[i], out[j] = out[j], out[i]
}
return string(out)
}
答案3
得分: 1
我已经在go-nuts线程上发布了。他们对我的建议似乎很满意。
同时 - 我的Base32实现(不处理符号 - 类似于nat
)
// 数字
const charset string = "0123456789ABCDEFGHIJKLMNOPQRSTUV"
/*
将大数转换为Base32
*/
func Base32(n big.Int) string {
// 数字的字节
bytes := n.Bytes()
nBytes := len(bytes)
if nBytes == 0 {
// 特殊情况0。
return "0"
}
// 字符串中将有多少个数字?
nBits := nBytes * 8
nDigits := nBits / 5
if nBits%5 > 0 {
nDigits += 1
}
// 将数字扩展为数组
digits := make([]byte, nDigits)
digit := nDigits - 1
// 每次从数组中取出5位。
for b, shr := nBytes-1, uint(0); b >= 0; {
// 下一批在那里。
shrp5 := shr + 5
// 构建我的位。
x := (bytes[b] >> shr)
if shrp5 > 8 && b > 0 {
of := shrp5 - 8
// 从下一个字节中添加一些位。
x &= (1 << (8 - shr)) - 1
x |= bytes[b-1] << (5 - of)
}
// 再移动5位。
shr = shrp5
// 我们是否应该跳到下一个字节?
if shr >= 8 {
// 下一个字节
shr -= 8
b -= 1
}
x &= 0x1f
// 构建我的数字
digits[digit] = charset[x]
digit -= 1
}
// 跳过前导零。
lz := 0
for digits[lz] == '0' {
lz += 1
}
// 返回等效的字符串。
return string(digits[lz:])
}
欢迎评论。
英文:
I have posted on the go-nuts thread. They seem happy with my suggestion.
Meanwhile - my implementation of Base32 (does NOT handle sign - like nat
)
// The digits
const charset string = "0123456789ABCDEFGHIJKLMNOPQRSTUV"
/*
Convert the big to base32
*/
func Base32(n big.Int) string {
// The bytes of the number
bytes := n.Bytes()
nBytes := len(bytes)
if nBytes == 0 {
// Special case 0.
return "0"
}
// How many digits will be in the string?
nBits := nBytes * 8
nDigits := nBits / 5
if nBits%5 > 0 {
nDigits += 1
}
// Grow the digits into an array
digits := make([]byte, nDigits)
digit := nDigits - 1
// Peel off 5 bits from the array each time.
for b, shr := nBytes-1, uint(0); b >= 0; {
// The next lot is there.
shrp5 := shr + 5
// Build my bits.
x := (bytes[b] >> shr)
if shrp5 > 8 && b > 0 {
of := shrp5 - 8
// Add in some bits from the next byte too.
x &= (1 << (8 - shr)) - 1
x |= bytes[b-1] << (5 - of)
}
// Shift 5 more.
shr = shrp5
// Should we step to next byte?
if shr >= 8 {
// Next byte
shr -= 8
b -= 1
}
x &= 0x1f
// Build my digit
digits[digit] = charset[x]
digit -= 1
}
// Skip leading zeros.
lz := 0
for digits[lz] == '0' {
lz += 1
}
// Return the string equivalent.
return string(digits[lz:])
}
Comments welcome.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论