【问题标题】:Show u8 slice in hex representation以十六进制表示形式显示 u8 切片
【发布时间】: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] 并使用它。谢谢回答。

标签: hex rust slice


【解决方案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::Debugfmt::Displayfmt::LowerHexfmt::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(&amp;[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

      【讨论】:

        猜你喜欢
        • 2016-04-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-06
        • 1970-01-01
        • 1970-01-01
        • 2014-12-20
        相关资源
        最近更新 更多