访问未导出的函数 `nat.string`

huangapple go评论171阅读模式
英文:

Acessing unexported function `nat.string`

问题

我想将一个big.Int转换为简单的base32格式。不是像base32实现的RFC 4648标准base32格式,也不是zBase32Crockford,我只想要每个字符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),它简单地调用具有正确charsetnat.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

Playground

英文:

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

Playground

答案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)
}

Playground链接

英文:

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 &quot;0&quot;
	}
	y := new(big.Int).Set(x)
	b := big.NewInt(int64(base))
	charset := &quot;0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ&quot;
	out := make([]byte, 0, 16)
	negative := false
	if y.Sign() &lt; 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, &#39;-&#39;)
	}
	// Reverse out
	for i, j := 0, len(out)-1; i &lt; j; i, j = i+1, j-1 {
		out[i], out[j] = out[j], out[i]
	}
	return string(out)
}

Playground link

答案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 = &quot;0123456789ABCDEFGHIJKLMNOPQRSTUV&quot;

/*
 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 &quot;0&quot;
	}
	// How many digits will be in the string?
	nBits := nBytes * 8
	nDigits := nBits / 5
	if nBits%5 &gt; 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 &gt;= 0; {
		// The next lot is there.
		shrp5 := shr + 5
		// Build my bits.
		x := (bytes[b] &gt;&gt; shr)
		if shrp5 &gt; 8 &amp;&amp; b &gt; 0 {
			of := shrp5 - 8
			// Add in some bits from the next byte too.
			x &amp;= (1 &lt;&lt; (8 - shr)) - 1
			x |= bytes[b-1] &lt;&lt; (5 - of)
		}
		// Shift 5 more.
		shr = shrp5
		// Should we step to next byte?
		if shr &gt;= 8 {
			// Next byte
			shr -= 8
			b -= 1
		}
		x &amp;= 0x1f
		// Build my digit
		digits[digit] = charset[x]
		digit -= 1
	}
	// Skip leading zeros.
	lz := 0
	for digits[lz] == &#39;0&#39; {
		lz += 1
	}
	// Return the string equivalent.
	return string(digits[lz:])
}

Comments welcome.

huangapple
  • 本文由 发表于 2013年10月7日 05:36:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/19214248.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定