Hexa to decimal conversion in Ruby - ruby

I have "\001\022" as value of a. my desired decimal value is 274.
I tried following function . but I get ["0112"]
a.unpack("H*") ==> ["0112"]
When I convert this "0112" to decimal using calculator it gives me 274. How can i get like
this using ruby methods.
Thanks

The format string in your question: "H*", is for "hex string (high nibble first)". Therefore it decoded your string as an array of 4-bit hexadecimal elements.
You need a different format.
Try this, which decodes it as a "16-bit unsigned, network (big-endian) byte order" integer:
a.unpack("n") # => [274]
For full details on what characters you can use in the format string, check the Ruby Documentation for String#unpack.

Related

Why does typecasting a single byte to string not work in go?

I am trying to convert a single byte value to a string in golang. When I do a typecast of a byte to string like string(byte) and print the value I get "{" in response. I read other answers that the correct way to convert a byte to string would be strconv.Itoa(int(bytevalue)). Why does the former not work and why is the latter approach correct.
The expression string(bytevalue) is a conversion, not a typecast.
The specification says this about conversions from numeric types to a string:
Converting a signed or unsigned integer value to a string type yields a string containing the UTF-8 representation of the integer.
The expression string(byte(123)) evaluates to the string "{" because { is the the string containing the UTF-8 representation of the rune 123.
Use the strconv package to get the decimal representation of the byte. The expression strconv.Itoa(int(byte(123))) evaluates to the string "123".

Conversion from hex to decimal in ruby

0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFE_FFFFFC2F.ord
=> 115792089237316195423570985008687907853269984665640564039457584007908834671663
0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFE_FFFFFC2F.to_i
=> 115792089237316195423570985008687907853269984665640564039457584007908834671663
Could somebody explain me why both of these methods return the same integer value?
I'm not sure that i understand the method ord...
Returns the codepoint of the first character of the string, assuming a single-byte character encoding"
I found that, but here I've go a hex value and i used the method then get a decimal value, so "What the hex?" :D
PS: Is it decimal value for sure or am I wrong?
You've quoted String#ord and here you call #ord on Integer - this value is not decimal, nor string, but integer.
Integer#ord docs:
ord → self
Returns the int itself.
97.ord #=> 97
This method is intended for compatibility to character literals in Ruby 1.9.

How do I convert hex to binary (and vice versa) in Ruby, WHILE maintaining leading zeroes?

I have a data structure that I'd like to convert back and forth from hex to binary in Ruby. The simplest approach for a binary to hex is '0010'.to_i(2).to_s(16) - unfortunately this does not preserve leading zeroes (due to the to_i call), as one may need with data structures like cryptographic keys (which also vary with the number of leading zeroes).
Is there an easy built in way to do this?
I think you should have a firm idea of how many bits are in your cryptographic key. That should be stored in some constant or variable in your program, not inside individual strings representing the key:
KEY_BITS = 16
The most natural way to represent a key is as an integer, so if you receive a key in a hex format you can convert it like this (leading zeros in the string do not matter):
key = 'a0a0'.to_i(16)
If you receive a key in a (ASCII) binary format, you can convert it like this (leading zeros in the string do not matter):
key = '101011'.to_i(2)
If you need to output a key in hex with the right number of leading zeros:
key.to_s(16).rjust((KEY_BITS+3)/4, '0')
If you need to output a key in binary with the right number of leading zeros:
key.to_s(2).rjust(KEY_BITS, '0')
If you really do want to figure out how many bits might be in a key based on a (ASCII) binary or hex string, you can do:
key_bits = binary_str.length
key_bits = hex_str.length * 4
The truth is, leading zeros are not part of the integer value. I mean, it's a little detail related to representation of this value, not the value itself. So if you want to preserve properties of representation, it may be best not to get to underlying values at all.
Luckily, hex<->binary conversion has one neat property: each hexadecimal digit exactly corresponds to 4 binary digits. So assuming you only get binary numbers that have number of digits divisible by 4 you can just construct two dictionaries for constructing back and forth:
# Hexadecimal part is easy
hex = [*'0'..'9', *'A'..'F']
# Binary... not much longer, but a bit trickier
bin = (0..15).map { |i| '%04b' % i }
Note the use of String#% operator, that formats the given value interpreting the string as printf-style format string.
Okay, so these are lists of "digits", 16 each. Now for the dictionaries:
hex2bin = hex.zip(bin).to_h
bin2hex = bin.zip(hex).to_h
Converting hex to bin with these is straightforward:
"DEADBEEF".each_char.map { |d| hex2bin[d] }.join
Converting back is not that trivial. I assume we have a "good number" that can be split into groups of 4 binary digits each. I haven't found a cleaner way than using String#scan with a "match every 4 characters" regex:
"10111110".scan(/.{4}/).map { |d| bin2hex[d] }.join
The procedure is mostly similar.
Bonus task: implement the same conversion disregarding my assumption of having only "good binary numbers", i. e. "110101".
"I-should-have-read-the-docs" remark: there is Hash#invert that returns a hash with all key-value pairs inverted.
This is the most straightforward solution I found that preserves leading zeros. To convert from hexadecimal to binary:
['DEADBEEF'].pack('H*').unpack('B*').first # => "11011110101011011011111011101111"
And from binary to hexadecimal:
['11011110101011011011111011101111'].pack('B*').unpack1('H*') # => "deadbeef"
Here you can find more information:
Array#pack: https://ruby-doc.org/core-2.7.1/Array.html#method-i-pack
String#unpack1 (similar to unpack): https://ruby-doc.org/core-2.7.1/String.html#method-i-unpack1

How to convert hexadecimal to base64urlsafe?

What would be the best way to convert a hexadecimal value (for instance a SHA-256 digest) into the base64urlsafe format?
Example:
f("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
# => "47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU="
The following should do it:
Base64.urlsafe_encode64(Array(hex_string).pack('H*'))
The method urlsafe_encode64 expects binary input, so you need to convert the hex representation to binary first, as shown above.
Use urlsafe_encode64 method:
require 'base64'
# The method urlsafe_encode64 expects binary input,
# so you need to convert the hex representation to binary
bin_string = [hex_string].pack('H*')
Base64.urlsafe_encode64 bin_string

Converting a hexadecimal number to binary in ruby

I am trying to convert a hex value to a binary value (each bit in the hex string should have an equivalent four bit binary value). I was advised to use this:
num = "0ff" # (say for eg.)
bin = "%0#{num.size*4}b" % num.hex.to_i
This gives me the correct output 000011111111. I am confused with how this works, especially %0#{num.size*4}b. Could someone help me with this?
You can also do:
num = "0ff"
num.hex.to_s(2).rjust(num.size*4, '0')
You may have already figured out, but, num.size*4 is the number of digits that you want to pad the output up to with 0 because one hexadecimal digit is represented by four (log_2 16 = 4) binary digits.
You'll find the answer in the documentation of Kernel#sprintf (as pointed out by the docs for String#%):
http://www.ruby-doc.org/core/classes/Kernel.html#M001433
This is the most straightforward solution I found to convert from hexadecimal to binary:
['DEADBEEF'].pack('H*').unpack('B*').first # => "11011110101011011011111011101111"
And from binary to hexadecimal:
['11011110101011011011111011101111'].pack('B*').unpack1('H*') # => "deadbeef"
Here you can find more information:
Array#pack: https://ruby-doc.org/core-2.7.1/Array.html#method-i-pack
String#unpack1 (similar to unpack): https://ruby-doc.org/core-2.7.1/String.html#method-i-unpack1
This doesn't answer your original question, but I would assume that a lot of people coming here are, instead of looking to turn hexadecimal to actual "0s and 1s" binary output, to decode hexadecimal to a byte string representation (in the spirit of such utilities as hex2bin). As such, here is a good method for doing exactly that:
def hex_to_bin(hex)
# Prepend a '0' for padding if you don't have an even number of chars
hex = '0' << hex unless (hex.length % 2) == 0
hex.scan(/[A-Fa-f0-9]{2}/).inject('') { |encoded, byte| encoded << [byte].pack('H2') }
end
Getting back to hex again is much easier:
def bin_to_hex(bin)
bin.unpack('H*').first
end
Converting the string of hex digits back to binary is just as easy. Take the hex digits two at a time (since each byte can range from 00 to FF), convert the digits to a character, and join them back together.
def hex_to_bin(s) s.scan(/../).map { |x| x.hex.chr }.join end

Resources