如何将字节数转换为字符串? (数字的字符表示)

时间:2017-03-24 07:29:17

标签: ruby string hex type-conversion character

如何轻松转换数字,例如{10}在基数10中等效0x616263,通过将数字除以连续字节而成为字符串?因此,上面的示例应转换为6382179

我已尝试Array.pack,但无法弄清楚如何让它转换为数字中的多个字节,例如'abc'返回[0x616263].pack("C*")。 我也试过了'c',但是抛出了一个ArgumentError:无效的基数。我想它需要某种编码信息?

(注意:像0x616263.to_s(256)这样的包中的其他数据类型与我上面给出的示例一致,但仅仅因为它适合4个字节,所以例如N给出[0x616263646566].pack("N"),而不是cdef abcdef

这个问题与this one模糊地相似,但不是真的。另外,我想弄清楚如何使用"abcde".unpack("c*").map{|c| c.to_s(16)}.join("")从字符串中获取十六进制表示字符串,这会给出'6162636465'。我基本上想要倒退。

我不认为这是X-Y problem,但如果是 - 我正在尝试将我用RSA解码的数字转换为字符串。

感谢您的帮助。我对Ruby没有太多经验。我也对Python解决方案感兴趣(为了好玩),但我不知道是否有权为这个问题添加两种不同编程语言的标签。

3 个答案:

答案 0 :(得分:4)

要将单个数字0x00616263转换为3个字符,您首先需要做的是将它们分成三个数字:0x000000610x000000620x00000063

对于最后一个数字,您想要的十六进制数字已经在正确的位置。但对于其他两个,你必须分别使用>> 16>> 8进行比特移位。

然后,使用按位并删除其他数字:

num1 = (0x616263 >> 16) & 0xFF
num2 = (0x616263 >> 8) & 0xFF
num3 = 0x616263 & 0xFF

对于角色,您可以这样做:

char1 = ((0x616263 >> 16) & 0xFF).chr
char2 = ((0x616263 >> 8) & 0xFF).chr
char3 = (0x616263 & 0xFF).chr

当然,按位操作不是Ruby特色。可能有其他人可能提供的类似Ruby的答案。

答案 1 :(得分:3)

64位整数

如果您的号码小于2 ** 64(8字节),您可以:

  • 转换" big-endian unsigned long long"到8个字节
  • 删除前导零字节

红宝石

[0x616263].pack('Q>').sub(/\x00+/,'')
# "abc"
[0x616263646566].pack('Q>').sub(/\x00+/,'')
# "abcdef"

Python 2& 3

在Python中,pack返回字节,而不是字符串。您可以decode()使用convert bytes to a String

import struct
import re
print(re.sub('\x00', '', struct.pack(">Q", 0x616263646566).decode()))
# abcdef
print(re.sub('\x00', '', struct.pack(">Q", 0x616263).decode()))
# abc

大号

使用gsub

如果您的号码不适合8个字节,则可以使用修改后的代码版本。这个更短,如果第一个字节小于10,则输出正确的字符串(例如,对于" \ t"):

def decode(int)
  if int < 2**64
    [int].pack('Q>').sub(/\x00+/, '')
  else
    nhex = int.to_s(16)
    nhex = '0' + nhex if nhex.size.odd?
    nhex.gsub(/../) { |hh| hh.to_i(16).chr }
  end
end

puts decode(0x616263) == 'abc'
# true
puts decode(0x616263646566) == 'abcdef'
# true
puts decode(0x0961) == "\ta"
# true
puts decode(0x546869732073656e74656e63652069732077617920746f6f206c6f6e6720666f7220616e20496e743634)
# This sentence is way too long for an Int64

顺便说一下,这是相反的方法:

def encode(str)
  str.reverse.each_byte.with_index.map { |b, i| b * 256**i }.inject(:+)
end

您仍应检查您的RSA代码是否确实输出任意大数字或仅输出整数数组。

随着班次

这是获得结果的另一种方式。它类似于@ Nathan的答案,但适用于任何整数:

def decode(int)
  a = []
  while int>0
    a << (int & 0xFF)
    int >>= 8
  end
  a.reverse.pack('C*')
end

根据fruity,它的速度是gsub解决方案的两倍。

答案 2 :(得分:2)

我目前正在努力:

n = 0x616263

nhex = n.to_s(16)
nhexarr = nhex.scan(/.{1,2}/)
nhexarr = nhexarr.map {|e| e.to_i(16)}

out = nhexarr.pack("C*")

但希望以简洁/内置的方式来做到这一点,所以我暂时不接受这个答案。