Ruby: create a String from bytes
41,076
Solution 1
There is a much simpler approach than any of the above: Array#pack:
>> [65,66,67,68,69].pack('c*')
=> "ABCDE"
I believe pack is implemented in c in matz ruby, so it also will be considerably faster with very large arrays.
Also, pack can correctly handle UTF-8 using the 'U*' template.
Solution 2
for 1.9 you need:
[195,164].pack('c*').force_encoding('UTF-8')
Solution 3
can't remember if there is a single function that does that:
>> a = [65,66,67]
=> [65, 66, 67]
>> a.map {|x| x.chr}.join
=> "ABC"
Solution 4
If bytes is an array of Fixnum's you could try this:
bytes.map {|num| num.chr}.join
or this:
s = ''
bytes.each {|i| s << i}
Related videos on Youtube
Author by
Vincent Robert
Excuse any English mistakes :-) I am on Twitter
Updated on November 19, 2020Comments
-
Vincent Robert over 3 years
I would like to build a string from a byte value.
I currently use:
str = " " str[0] = byte
This seems to work fine but I find it ugly and not very scalable to strings longer than 1 character.
Any idea?
-
Vincent Robert about 15 yearsNice, did not know about the chr method
-
severin almost 12 yearsThis answer describes the correct way to do it. But remember to set the encoding correctly in Ruby 1.9 as the answer by grosser points out!
-
David J. almost 12 years@VincentRobert How can you / can you do this example in that style?
[195,164].pack('c*').force_encoding('UTF-8')
-
David J. almost 12 yearsGot it:
[195,164].map { |x| x.chr }.join.force_encoding('UTF-8')
-
David J. almost 12 yearsYou got 'lucky' with the lowercase
c*
. You really wantC*
. See: ruby-doc.org/core-1.9.3/Array.htmlc
is for "8-bit signed (signed char)",C
is for "8-bit unsigned (unsigned char)" -
David J. almost 12 yearsI recommend using
C*
because you want unsigned integers.c*
is for signed integers. Note that:"ä".unpack('c*')
==[-61, -92]
. What you want is:"ä".unpack('C*')
==[195, 164]
-
stephenjudkins over 11 yearsPack can NOT correctly handle UTF-8 using the "U*" template. This is incorrect. "U*" packs an array of Unicode codepoints, not UTF8 bytes.
-
A. Wilson almost 11 years@DavidJames can you demonstrate a case where C* works and c* doesn't? All unicode has a 1 in GSB and is therefore "signed", right? But this works fine: irb(main):001:0> puts ["11010111", "10101010"].map{|x|x.to_i(2)}.pack('c*') # (gives the string "ת")
-
David J. almost 11 years@A.Wilson see my example in the comments for stackoverflow.com/a/4701955/109618
-
A. Wilson almost 11 yearsI did see that, I was wondering specifically if it ever made a difference with pack (rather than unpack). This is still important to avoid confusion, I recognize, I'm just wondering if that's the only reason for the caveat
-
sscirrus almost 8 yearsMore compact:
a.map(&:chr).join