Go:将符文(字符串)转换为二进制的字符串表示形式
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
包,只需将 rune
格式化为 %b%
:
var r rune
fmt.Printf("input: %b ", r)
有更好的方法吗?
谢谢
标准库支持
fmt.Printf("%b", r)
- 这个解决方案已经非常紧凑,易于编写和理解。如果您需要结果作为 string
,您可以使用模拟 Sprintf()
函数:
s := fmt.Sprintf("%b", r)
您还可以使用 strconv.FormatInt()
函数,该函数接受 int64
类型的数字(因此您首先必须转换 rune
)和一个可以传递 2
得到二进制表示的结果:
s := strconv.FormatInt(int64(r), 2)
请注意,在 Go 中 rune
只是 int32
的别名,这两种类型是相同的(只是您可以通过 2 个名称来引用它)。
手动执行 ("Simple but Naive"):
如果您想这样做 "manually",有一个比您原来的解决方案简单得多的解决方案。您可以使用 r & 0x01 == 0
测试最低位,并使用 r >>= 1
移动所有位。只需 "loop" 覆盖所有位并根据位附加 "1"
或 "0"
:
请注意,这只是为了演示,它在性能方面远未达到最佳状态(生成 "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
}
注意:函数不处理负数。如果您还想处理负数,您可以先检查它,然后处理它的正值,并以负号 '-'
开始 return 值。这也适用于下面的其他手动解决方案。
手动性能解决方案:
为了获得快速解决方案,我们不应附加字符串。由于 Go 中的字符串只是使用 UTF-8 编码的字节切片,附加一个数字只是附加符文 '0'
或 '1'
的字节值,这只是一个字节(不是多字节)。所以我们可以分配一个足够大的 buffer/array (rune
是 32 位,所以最多 32 个二进制数字),并向后填充它,这样我们甚至不必在最后反转它。并且 return 数组的使用部分在最后转换为 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:])
}
这是为了防止其他人正在学习 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
包,只需将 rune
格式化为 %b%
:
var r rune
fmt.Printf("input: %b ", r)
有更好的方法吗?
谢谢
标准库支持
fmt.Printf("%b", r)
- 这个解决方案已经非常紧凑,易于编写和理解。如果您需要结果作为 string
,您可以使用模拟 Sprintf()
函数:
s := fmt.Sprintf("%b", r)
您还可以使用 strconv.FormatInt()
函数,该函数接受 int64
类型的数字(因此您首先必须转换 rune
)和一个可以传递 2
得到二进制表示的结果:
s := strconv.FormatInt(int64(r), 2)
请注意,在 Go 中 rune
只是 int32
的别名,这两种类型是相同的(只是您可以通过 2 个名称来引用它)。
手动执行 ("Simple but Naive"):
如果您想这样做 "manually",有一个比您原来的解决方案简单得多的解决方案。您可以使用 r & 0x01 == 0
测试最低位,并使用 r >>= 1
移动所有位。只需 "loop" 覆盖所有位并根据位附加 "1"
或 "0"
:
请注意,这只是为了演示,它在性能方面远未达到最佳状态(生成 "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
}
注意:函数不处理负数。如果您还想处理负数,您可以先检查它,然后处理它的正值,并以负号 '-'
开始 return 值。这也适用于下面的其他手动解决方案。
手动性能解决方案:
为了获得快速解决方案,我们不应附加字符串。由于 Go 中的字符串只是使用 UTF-8 编码的字节切片,附加一个数字只是附加符文 '0'
或 '1'
的字节值,这只是一个字节(不是多字节)。所以我们可以分配一个足够大的 buffer/array (rune
是 32 位,所以最多 32 个二进制数字),并向后填充它,这样我们甚至不必在最后反转它。并且 return 数组的使用部分在最后转换为 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:])
}