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

问题描述 投票:0回答:3

如何轻松转换数字,例如

0x616263
,相当于以 10 为基数的
6382179
,通过将数字分成连续的字节来转换为字符串?所以上面的例子应该转换成
'abc'

我已经尝试过 Array.pack 但无法弄清楚如何让它转换数字中的多个字节,例如

[0x616263].pack("C*")
返回
'c'
。 我也尝试过
0x616263.to_s(256)
,但这会引发 ArgumentError: invalid radix。我想它需要某种编码信息?

(注意:包中的其他数据类型(如

N
)适用于我上面给出的示例,但只是因为它适合 4 个字节,因此例如
[0x616263646566].pack("N")
给出
cdef
,而不是
abcdef

这个问题与这个问题隐约相似,但并非如此。另外,我还想出了如何使用

"abcde".unpack("c*").map{|c| c.to_s(16)}.join("")
从字符串中获取十六进制表示字符串,这给出了
'6162636465'
。我基本上想倒退。

我不认为这是一个 X-Y 问题,但万一它是 - 我正在尝试将用 RSA 解码的数字转换为字符串。

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

ruby string hex type-conversion character
3个回答
5
投票

要将单个数字

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

对于最后一个数字,您想要的十六进制数字已经位于正确的位置。但对于另外两个,您必须分别使用

>> 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 的答案。


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()
将字节转换为字符串 :

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(例如“”),这会更短并正确输出字符串:

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
投票

我目前正在研究这个:

n = 0x616263

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

out = nhexarr.pack("C*")

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

© www.soinside.com 2019 - 2024. All rights reserved.