如何在Ruby中访问方法链的返回值?

时间:2011-08-01 06:36:25

标签: ruby

例如

str = 'f01288c2' #a hexadecimal string
bin = str.to_i(16).to_s(2).rjust(str.length + (64 - (str.length % 64)), '0')

因此二进制字符串的大小始终是64的乘法 这里的问题是,str.length是转换成二进制之前的长度。我需要to_s(2)之后的字符串长度。如何访问to_s(2)的返回值?

更新 我想知道是否有单链解决方案。

7 个答案:

答案 0 :(得分:4)

单行解决方案将使用Kernel#tapstr.replace

ruby > str = 'f01288c2' #a hexadecimal string
 => "f01288c2" 
ruby > bin = str.to_i(16).to_s(2).rjust(str.length + (64 - (str.length % 64)), '0')
 => "0000000000000000000000000000000011110000000100101000100011000010" 
ruby > bin = str.to_i(16).to_s(2).tap { |str| str.replace str.rjust(str.length + (64 - (str.length % 64)), '0') }
 => "11110000000100101000100011000010" 

答案 1 :(得分:2)

您必须将其拆分为两行:

str = 'f01288c2' #a hexadecimal string
len = str.to_i(16).to_s(2)
bin = len.rjust(str.length + (64 - (str.lenght % 64)), '0')

答案 2 :(得分:2)

您是否需要该值本身,或者您是否需要它来进行结果箱的长度计算?

也许这解决了你的问题(但不是你的答案):

str = 'f01288c2' #a hexadecimal string
bin = "%0*b" % [str.length + (64 - (str.length % 64)),str.to_i(16)]

基于我的其他'answer'以及一些想法,我对问题进行了单元测试并结合了答案。我发现没有正确的单线。在方法my_solution中我至少有一些代码,我的测试说好了。我希望我的测试设计是正确的;)

gem 'test-unit'
require 'test/unit'

def original(str) #from https://stackoverflow.com/questions/6894901/how-to-access-return-value-of-a-method-chain-in-ruby
  str.to_i(16).to_s(2).rjust(str.length + (64 - (str.length % 64)), '0')
end
def whitequark_1(str) #accepted: https://stackoverflow.com/questions/6894901/how-to-access-return-value-of-a-method-chain-in-ruby/6894974#6894974
  str.to_i(16).to_s(2).tap { |str| str.replace str.rjust(str.length + (64 - (str.length % 64)), '0') }
end  
def whitequark_2(str) #accepted: https://stackoverflow.com/questions/6894901/how-to-access-return-value-of-a-method-chain-in-ruby/6894974#6894974
  str.to_i(16).to_s(2).rjust(str.length + (64 - (str.length % 64)), '0')
end
def yossi(str)  #https://stackoverflow.com/questions/6894901/how-to-access-return-value-of-a-method-chain-in-ruby/6894943#6894943
  len = str.to_i(16).to_s(2)
  #~ len.rjust(str.length + (64 - (str.lenght % 64)), '0')
  len.rjust(str.size + (64 - (str.size% 64)), '0')
end
def my_solution(str)  #
  size1 = ("%0b" % str.to_i(16).to_s).size
  size2 = 64 * ( size1 / 64 + [1, size1 % 64 ].min)
  "%0*b" % [size2, str.to_i(16)]
end

#Select the version you want to check
#~ alias :experiment :original #wrong
#~ alias :experiment :yossi
#~ alias :experiment :whitequark_1 #wrong with f01288c2_f01288c2
#~ alias :experiment :whitequark_2  #wrong with f_f01288c2_f01288c2
alias :experiment :my_solution

#Testcases for different Test-setups.
module MyTestcases
  def test_binary()
    assert_match( /\A[01]+\Z/, @bin)
  end
  def test_solution()
    pend "No solution defined #{@bin}" unless defined? @solution
    assert_equal( 0, @solution.size % 64)
    assert_equal( @bin.to_i(2), @solution.to_i(2))
    assert_equal( @str, @solution.to_i(2).to_s(16))
    assert_equal( @solution, @bin)
  end
  def test_multiply64()
    assert_equal( 0, @bin.size % 64, 'no multiply of 64')
  end
  def test_smallest64()
    size = ("%b" % @str.to_i(16)).size
    smallestsize = 0
    #determine smallest 
    while smallestsize < size
      smallestsize += 64
    end
    assert_equal( smallestsize, @bin.size, 'not smallest multiply of 64')
  end
end

class MyTest_00000001 < Test::Unit::TestCase
  def setup
    @str = '1' #a hexadecimal string
    @bin = experiment(@str)
    @solution = "0000000000000000000000000000000000000000000000000000000000000001"
  end
  include MyTestcases
end
class MyTest_f01288c2 < Test::Unit::TestCase
  def setup
    @str = 'f01288c2' #a hexadecimal string
    @bin = experiment(@str)
    @solution = "0000000000000000000000000000000011110000000100101000100011000010"
  end
  include MyTestcases
end
class MyTest_ff01288c2 < Test::Unit::TestCase
  def setup
    @str = 'ff01288c2' #a hexadecimal string
    @bin = experiment(@str)
    @solution = "0000000000000000000000000000111111110000000100101000100011000010"
  end
  include MyTestcases
end
class MyTest_f01288c2_f01288c2 < Test::Unit::TestCase
  def setup
    @str = 'f01288c2f01288c2' #a hexadecimal string
    @bin = experiment(@str)
    @solution = "1111000000010010100010001100001011110000000100101000100011000010"
  end
  include MyTestcases
end
class MyTest_f_f01288c2_f01288c2 < Test::Unit::TestCase
  def setup
    @str = 'ff01288c2f01288c2' #a hexadecimal string
    @bin = experiment(@str)
    @solution = "00000000000000000000000000000000000000000000000000000000000011111111000000010010100010001100001011110000000100101000100011000010"
  end
  include MyTestcases
end

答案 3 :(得分:1)

也许我错过了什么,但你可以通过这样做很容易地访问to_s(2)的返回值:

r = str.to_i(16).to_s(2)

答案 4 :(得分:1)

在实际代码中,您将使用中间行来分配长度(请参阅@ Yossi的答案),这是正确的方法。现在,如果你想要一种方法来做一个有趣的单行程,那么你可以使用例如Object#as抽象(在某些情况下实际上相当有用)

class Object
  def as
    yield self
  end
end

str = 'f01288c2'
len, bin = str.to_i(16).to_s(2).as { |len| [len, len.rjust(str.length + (64-(str.length%64)), '0') }

答案 5 :(得分:0)

这不是'回答',而是一个问题 - 对于评论来说有点太长了。

  

因此二进制字符串的大小始终是64的乘法。

你的str.length +(64 - (str.length%64))应该是64的倍数,所以二进制字符串适合吗?

对于'11f01288c2'(10个字符),它应该是128?对? (64是小,所以你需要128) 但是你的计算结果是64。

我这边有误会吗?

这里是一个代码示例(以及另一个计算的快速版本 - 也许是更好的一个):

str = '11f01288c2' #a hexadecimal string
p (str.length + (64 - (str.length % 64)))  #-> 64
p 64 * ((str.length * 8).divmod(64).first + 1) #-> 128
p 64 * ((str.length).divmod(8).first + 1) #-> 128

答案 6 :(得分:0)

我认为你想要的计算是:

(str.length / 64.0).ceil * 64

你的字符串将产生不必要的64 0,这些字符串已经是64长的偶数倍。

您遇到的问题是您尝试将rjust视为一个块,以便您可以访问其接收器。但是因为它是一个方法,所以它的参数在被调用之前就会被计算出来。因此,将其转换为单行的方法是将其转换,创建一个匿名函数,然后在字符串上调用它:

lambda {|x| x.rjust((x.length / 64.0).ceil * 64, '0')}.call(str.to_i(16).to_s(2))

对我来说实际上有点令人费解的是,没有内置的方法来调用Ruby中的对象上的块,比如tap但是返回块的结果。 (我错过了什么吗?)

但我们当然可以轻松创建一个:

class Object
  def doblock
    block_given? ? yield self : self
  end
end

那将让我们做(除其他事项外):

str.to_i(16).to_s(2).doblock {|x| x.rjust((x.length / 64.0).ceil * 64, '0')}