如何在Ruby中将字符串或整数转换为二进制?

195

如何将0到9的整数以及加、减、乘、除等数学运算符转换成二进制字符串。

例如:

 0 = 0000,
 1 = 0001, 
 ...
 9 = 1001

有没有一种不使用库的方法可以在Ruby 1.8.6中实现这个功能?


当你说要将数学运算符转换为二进制字符串时,你确切指的是什么?使用二进制编写的ASCII表示吗? - bta
我猜你想做流行的遗传算法? :-) - JWL
8个回答

430

您可以使用Integer#to_s(base)String#to_i(base)方法。

Integer#to_s(base)将十进制数转换为特定基数的字符串:

9.to_s(2) #=> "1001"

使用String#to_i(base)可以得到反向结果:

"1001".to_i(2) #=> 9

28
此外,您可以使用 ("%08b" % int)("%08b" % string) 返回固定数量的位。 - jrdi
1
了不起的 Mike,了不起的 Ruby! - Tamer Shlash
5
-9.to_s(2) 的意思是将数字 -9 转换为二进制并转换为字符串。=> "-1001" 是表示二进制数的字符串,其中第一位是符号位(0表示正数,1表示负数),后面的三个数字是二进制表示的绝对值。 - user1201917
1
对于像我一样被@decay的代码搞糊涂的人,他是在使用'sprintf':https://apidock.com/ruby/Kernel/sprintf - Taylor Liss
@user1201917 太棒了!我必须说,我很少遇到负二进制数,但至少当我在数学中看到它们时,符号“-1001”对于“-9”是正确的。程序员之间是否有一些更常见的带符号位或其他符号表示法呢? - preferred_anon
显示剩余3条评论

47

我曾经问过一个类似的问题。根据@sawa的答案,将整数以二进制格式表示为字符串的最简洁方式是使用字符串格式化程序:

"%b" % 245
=> "11110101"

您还可以选择字符串表示的长度,这可能对于想要比较固定宽度的二进制数字的情况很有用:

1.upto(10).each { |n| puts "%04b" % n }
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010

8
我做了一些本地测试,将整数转换为二进制字符串,结果显示像245.to_s(2)这样的代码比"%b" % 245更快。 - Green Su
1
同时,这个方法不能正确处理负数值。 - alex

23

借鉴bta的查找表思路,你可以使用块创建查找表。当值第一次被访问时生成并存储以供后续调用:

>> lookup_table = Hash.new { |h, i| h[i] = i.to_s(2) }
=> {}
>> lookup_table[1]
=> "1"
>> lookup_table[2]
=> "10"
>> lookup_table[20]
=> "10100"
>> lookup_table[200]
=> "11001000"
>> lookup_table
=> {1=>"1", 200=>"11001000", 2=>"10", 20=>"10100"}

11

在实际编程中,您自然会使用Integer#to_s(2)String#to_i(2)"%b"。但是,如果您对翻译的工作方式感兴趣,此方法使用基本运算符计算给定整数的二进制表示:

def int_to_binary(x)
  p = 0
  two_p = 0
  output = ""

  while two_p * 2 <= x do
    two_p = 2 ** p
    output << ((two_p & x == two_p) ? "1" : "0")
    p += 1
  end

  #Reverse output to match the endianness of %b
  output.reverse
end

要检查它是否正常工作:

1.upto(1000) do |n|
  built_in, custom = ("%b" % n), int_to_binary(n)
  if built_in != custom
    puts "I expected #{built_in} but got #{custom}!"
    exit 1
  end
  puts custom
end

4

如果你只处理0-9的单个数字,那么构建一个查找表可能会更快,这样就不必每次调用转换函数了。

lookup_table = Hash.new
(0..9).each {|x|
    lookup_table[x] = x.to_s(2)
    lookup_table[x.to_s] = x.to_s(2)
}
lookup_table[5]
=> "101"
lookup_table["8"]
=> "1000"

使用数字的整数或字符串表示法来索引此哈希表,将产生其二进制表示作为字符串。

如果您需要二进制字符串具有特定数量的位数(保留前导零),则将x.to_s(2)更改为sprintf“%04b”,x (其中4 是要使用的最小位数)。


@bta- 我正在将所有这些字符编码为二进制,以便我可以在遗传算法中使用它们。我非常喜欢使用查找表进行编码/解码的想法,因为集合仅限于0..9和+-*/。 - mcmaloney

4
在 Ruby 的 Integer 类中,to_s 方法被定义为接收一个名为“base”的非必需参数。如果您希望得到字符串的二进制表示,请传递数字 2。
以下是String#to_s的官方文档链接。
  1.upto(10).each { |n|  puts n.to_s(2) }

1
如果您能编辑并描述代码如何解决问题,那么这个答案将显著改善。 - Cleptus

2

如果您正在寻找一个Ruby类/方法,我使用了这个,并且我也包括了测试:

class Binary
  def self.binary_to_decimal(binary)
    binary_array = binary.to_s.chars.map(&:to_i)
    total = 0

    binary_array.each_with_index do |n, i|
      total += 2 ** (binary_array.length-i-1) * n
    end
    total
   end
end

class BinaryTest < Test::Unit::TestCase
  def test_1
   test1 = Binary.binary_to_decimal(0001)
   assert_equal 1, test1
  end

 def test_8
    test8 = Binary.binary_to_decimal(1000)
    assert_equal 8, test8
 end

 def test_15
    test15 = Binary.binary_to_decimal(1111)
    assert_equal 15, test15
 end

 def test_12341
    test12341 = Binary.binary_to_decimal(11000000110101)
    assert_equal 12341, test12341
 end
end

-1

我可能晚了将近十年,但如果有人仍然来到这里并想找到不使用内置函数(如to_S)的代码,则我可能会有所帮助。

找到二进制文件

def find_binary(number)
  binary = []  
  until(number == 0)
    binary << number%2
    number = number/2
  end
  puts binary.reverse.join
end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接