Go:将rune(字符串)转换为二进制的字符串表示形式

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

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 &lt; len(b); i++ {
	    t := v-b[i]
	    if t &gt;= 0 {
		   fmt.Fprintf(&amp;buf, &quot;1&quot;)
		   v = t
	    } else {
		   fmt.Fprintf(&amp;buf, &quot;0&quot;)
	    }
    }

    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(&quot;input: %b &quot;, 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(&quot;%b&quot;, 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(&quot;%b&quot;, 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 &amp; 0x01 == 0 and shift all bits with r &gt;&gt;= 1. Just "loop" over all bits and append either &quot;1&quot; or &quot;0&quot; depending on the bit:

Note this is just for demonstration, it is nowhere near optimal regarding performance (generates "redundant" strings):

func RuneToBin(r rune) (s string) {
	if r == 0 {
		return &quot;0&quot;
	}
	for digits := []string{&quot;0&quot;, &quot;1&quot;}; r &gt; 0; r &gt;&gt;= 1 {
		s = digits[r&amp;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 &#39;-&#39; 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 &#39;0&#39; or &#39;1&#39; 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 &quot;0&quot;
	}
	b, i := [32]byte{}, 31
	for ; r &gt; 0; r, i = r&gt;&gt;1, i-1 {
		if r&amp;1 == 0 {
			b[i] = &#39;0&#39;
		} else {
			b[i] = &#39;1&#39;
		}
	}
	return string(b[i+1:])
}

huangapple
  • 本文由 发表于 2015年2月22日 22:51:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/28659193.html
匿名

发表评论

匿名网友

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

确定