以十六进制表示形式显示 u8 切片
Posted
技术标签:
【中文标题】以十六进制表示形式显示 u8 切片【英文标题】:Show u8 slice in hex representation 【发布时间】:2015-02-23 08:43:19 【问题描述】:我需要将&[u8]
转换为十六进制表示。例如[ A9, 45, FF, 00 ... ]
。
特征std::fmt::UpperHex
没有为切片实现(所以我不能使用std::fmt::format
)。 Rust 具有 serialize::hex::ToHex
特征,它将 &[u8]
转换为十六进制字符串,但我需要一个带有单独字节的表示。
我可以自己为&[u8]
实现特征UpperHex
,但我不确定这将是多么规范。最规范的方法是什么?
【问题讨论】:
当你说“十六进制表示”时,你的意思是你想要一个字符串吗?还是什么类型? 顺便说一句,你不能为&[u8]
实现UpperHex
,因为特征和类型都不是“你的”(它们都没有在你的板条箱中定义)。您可以为&[u8]
的新类型实现UpperHex
(例如struct HexSlice<'a>(&'a [u8])
,但这可能会很不方便。定义一个简单的函数会更好。
Vladimir Matveev,我的意思是创建新类型,其中包含 [u8] 并使用它。谢谢回答。
【参考方案1】:
Rust 1.26.0 及更高版本
可以使用:x?
“使用十六进制整数调试”格式化程序:
let data = b"hello";
// lower case
println!(":x?", data);
// upper case
println!(":X?", data);
let data = [0x0, 0x1, 0xe, 0xf, 0xff];
// print the leading zero
println!(":02X?", data);
// It can be combined with the pretty modifier as well
println!(":#04X?", data);
输出:
[68, 65, 6c, 6c, 6f]
[68, 65, 6C, 6C, 6F]
[00, 01, 0E, 0F, FF]
[
0x00,
0x01,
0x0E,
0x0F,
0xFF,
]
如果您需要更多控制或需要支持旧版本的 Rust,请继续阅读。
Rust 1.0 及更高版本
use std::fmt::Write;
fn main()
let mut s = String::new();
for &byte in "Hello".as_bytes()
write!(&mut s, ":X ", byte).expect("Unable to write");
println!("", s);
这可以通过在包装结构上实现格式特征之一(fmt::Debug
、fmt::Display
、fmt::LowerHex
、fmt::UpperHex
等)并具有一个小构造函数来实现:
use std::fmt;
struct HexSlice<'a>(&'a [u8]);
impl<'a> HexSlice<'a>
fn new<T>(data: &'a T) -> HexSlice<'a>
where
T: ?Sized + AsRef<[u8]> + 'a,
HexSlice(data.as_ref())
// You can choose to implement multiple traits, like Lower and UpperHex
impl fmt::Display for HexSlice<'_>
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
for byte in self.0
// Decide if you want to pad the value or have spaces inbetween, etc.
write!(f, ":X ", byte)?;
Ok(())
fn main()
// To get a `String`
let s = format!("", HexSlice::new("Hello"));
// Or print it directly
println!("", HexSlice::new("world"));
// Works with
HexSlice::new("Hello"); // string slices (&str)
HexSlice::new(b"Hello"); // byte slices (&[u8])
HexSlice::new(&"World".to_string()); // References to String
HexSlice::new(&vec![0x00, 0x01]); // References to Vec<u8>
您甚至可以更花哨并创建一个扩展特征:
trait HexDisplayExt
fn hex_display(&self) -> HexSlice<'_>;
impl<T> HexDisplayExt for T
where
T: ?Sized + AsRef<[u8]>,
fn hex_display(&self) -> HexSlice<'_>
HexSlice::new(self)
fn main()
println!("", "world".hex_display());
【讨论】:
格式字符串不应该是":02X"
,以确保为每个字符打印两个十六进制字符(如果需要,包括第一个0
)?
@phoenix 是的,如果需要的话。这就是我所说的评论“决定是否要在此处填充值”的意思。
您需要":02x?"
。它仍然将其打印为逗号分隔的列表。 :-/
是的,提醒人们如果您要将生成的字符串粘贴到十六进制编辑器等,您需要使用 :02X?
进行零填充。只是浪费了很多时间来弄清楚为什么我得到了垃圾值。【参考方案2】:
由于接受的答案在 Rust 1.0 稳定版上不起作用,这是我的尝试。应该是无分配的,因此相当快。这基本上是 [u8] 的格式化程序,但是由于一致性规则,我们必须将 [u8]
包装成自定义类型 ByteBuf(&[u8])
才能使用它:
struct ByteBuf<'a>(&'a [u8]);
impl<'a> std::fmt::LowerHex for ByteBuf<'a>
fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error>
for byte in self.0
try!( fmtr.write_fmt(format_args!(":02x", byte)));
Ok(())
用法:
let buff = [0_u8; 24];
println!(":x", ByteBuf(&buff));
【讨论】:
【参考方案3】:有一个箱子:hex-slice。
例如:
extern crate hex_slice;
use hex_slice::AsHex;
fn main()
let foo = vec![0u32, 1, 2 ,3];
println!(":02x", foo.as_hex());
【讨论】:
【参考方案4】:这是我的解决方案,看起来还不错:
fn main()
let data = vec![27u8, 34, 42, 56, 88];
println!(
"0x",
data.iter()
.map(|b| format!(":02X", *b))
.collect::<Vec::<_>>()
.join("")
);
打印0x1B222A3858
。
【讨论】:
以上是关于以十六进制表示形式显示 u8 切片的主要内容,如果未能解决你的问题,请参考以下文章
以IEEE754短浮点数格式表示十进制数:-3.125 要求写出过程,并最终用十六进制缩写形式表示