英文:
Go: convert rune (string) to string representation of the binary
问题
这是为了防止其他人学习Golang并想知道如何将字符串转换为二进制字符串表示时的情况。
长话短说,我一直在查看标准库,但找不到正确的调用方法。所以我从类似下面的代码开始:
func RuneToBinary(r rune) string {
var buf bytes.Buffer
b := []int64{128, 64, 32, 16, 8, 4, 2, 1}
v := int64(r)
for i := 0; i < len(b); i++ {
t := v - b[i]
if t >= 0 {
fmt.Fprintf(&buf, "1")
v = t
} else {
fmt.Fprintf(&buf, "0")
}
}
return buf.String()
}
这样做也可以,但是经过几天的搜索后,我发现我应该使用fmt
包,只需使用%b
格式化rune
:
var r rune
fmt.Printf("input: %b ", r)
有更好的方法吗?
谢谢
英文:
This is just in case someone else is learning Golang and is wondering how to convert from a string to a string representation in binary.
Long story short, I have been looking at the standard library without being able to find the right call. So I started with something similar to the following:
func RuneToBinary(r rune) string {
var buf bytes.Buffer
b := []int64{128, 64, 32, 16, 8, 4, 2, 1}
v := int64(r)
for i := 0; i < len(b); i++ {
t := v-b[i]
if t >= 0 {
fmt.Fprintf(&buf, "1")
v = t
} else {
fmt.Fprintf(&buf, "0")
}
}
return buf.String()
}
This is all well and dandy, but after a couple of days looking around I found that I should have been using the fmt
package instead and just format the rune
with %b%
:
var r rune
fmt.Printf("input: %b ", r)
Is there a better way to do this?
Thanks
答案1
得分: 6
标准库支持
fmt.Printf("%b", r)
- 这个解决方案已经非常简洁易懂了。如果你需要将结果作为一个string
,你可以使用类似的Sprintf()
函数:
s := fmt.Sprintf("%b", r)
你也可以使用strconv.FormatInt()
函数,它接受一个int64
类型的数字(所以你首先需要将你的rune
转换为int64
),并且可以传入2
作为基数,以获取二进制表示的结果:
s := strconv.FormatInt(int64(r), 2)
请注意,在Go语言中,rune
只是int32
的别名,这两种类型是相同的(只是你可以用两个名称来引用它)。
手动实现("简单但是朴素")
如果你想要手动实现,有一个比你原来的解决方案更简单的方法。你可以使用r & 0x01 == 0
来测试最低位,并使用r >>= 1
来移动所有位。只需遍历所有位,并根据位的值附加"1"
或"0"
:
请注意,这只是为了演示,从性能上来说远非最优(生成了"冗余"的string
):
func RuneToBin(r rune) (s string) {
if r == 0 {
return "0"
}
for digits := []string{"0", "1"}; r > 0; r >>= 1 {
s = digits[r&1] + s
}
return
}
注意:该函数不处理负数。如果你也想处理负数,你可以先检查它并处理它的正值,并将返回值以负号'-'
开头。下面的另一个手动解决方案也适用于这一点。
手动优化性能的解决方案
为了快速解决问题,我们不应该附加字符串。由于Go语言中的字符串只是使用UTF-8编码的字节切片,附加一个数字只是附加'0'
或'1'
的字节值,这只是一个字节(不是多个字节)。因此,我们可以分配一个足够大的缓冲区/数组(rune
是32位的,所以最多有32个二进制位),并向后填充它,这样我们甚至不需要在最后进行反转。然后在最后返回数组的使用部分转换为string
。请注意,我甚至没有调用内置的append
函数来附加二进制位,我只是设置了构建结果的数组中的相应元素:
func RuneToBinFast(r rune) string {
if r == 0 {
return "0"
}
b, i := [32]byte{}, 31
for ; r > 0; r, i = r>>1, i-1 {
if r&1 == 0 {
b[i] = '0'
} else {
b[i] = '1'
}
}
return string(b[i+1:])
}
英文:
Standard library support
fmt.Printf("%b", r)
- this solution is already very compact and easy to write and understand. If you need the result as a string
, you can use the analog Sprintf()
function:
s := fmt.Sprintf("%b", r)
You can also use the strconv.FormatInt()
function which takes a number of type int64
(so you first have to convert your rune
) and a base where you can pass 2
to get the result in binary representation:
s := strconv.FormatInt(int64(r), 2)
Note that in Go rune
is just an alias for int32
, the 2 types are one and the same (just you may refer to it by 2 names).
Doing it manually ("Simple but Naive"):
If you'd want to do it "manually", there is a much simpler solution than your original. You can test the lowest bit with r & 0x01 == 0
and shift all bits with r >>= 1
. Just "loop" over all bits and append either "1"
or "0"
depending on the bit:
Note this is just for demonstration, it is nowhere near optimal regarding performance (generates "redundant" string
s):
func RuneToBin(r rune) (s string) {
if r == 0 {
return "0"
}
for digits := []string{"0", "1"}; r > 0; r >>= 1 {
s = digits[r&1] + s
}
return
}
Note: negative numbers are not handled by the function. If you also want to handle negative numbers, you can first check it and proceed with the positive value of it and start the return value with a minus '-'
sign. This also applies the other manual solution below.
Manual Performance-wise solution:
For a fast solution we shouldn't append strings. Since strings in Go are just byte slices encoded using UTF-8, appending a digit is just appending the byte value of the rune '0'
or '1'
which is just one byte (not multi). So we can allocate a big enough buffer/array (rune
is 32 bits so max 32 binary digits), and fill it backwards so we won't even have to reverse it at the end. And return the used part of the array converted to string
at the end. Note that I don't even call the built-in append
function to append the binary digits, I just set the respective element of the array in which I build the result:
func RuneToBinFast(r rune) string {
if r == 0 {
return "0"
}
b, i := [32]byte{}, 31
for ; r > 0; r, i = r>>1, i-1 {
if r&1 == 0 {
b[i] = '0'
} else {
b[i] = '1'
}
}
return string(b[i+1:])
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论