Show u8 slice in hex representation

后端 未结 3 447
清酒与你
清酒与你 2020-11-28 14:26

I need to convert &[u8] to a hex representation. For example [ A9, 45, FF, 00 ... ].

The trait std::fmt::UpperHex is not i

相关标签:
3条回答
  • 2020-11-28 14:41

    There's a crate for this: hex-slice.

    For example:

    extern crate hex_slice;
    use hex_slice::AsHex;
    
    fn main() {
        let foo = vec![0u32, 1, 2 ,3];
        println!("{:02x}", foo.as_hex());
    }
    
    0 讨论(0)
  • 2020-11-28 14:49

    Rust 1.26.0 and up

    The :x? "debug with hexadecimal integers" formatter can be used:

    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);
    

    Output:

    [68, 65, 6c, 6c, 6f]
    [68, 65, 6C, 6C, 6F]
    [00, 01, 0E, 0F, FF]
    [
        0x00,
        0x01,
        0x0E,
        0x0F,
        0xFF,
    ]
    

    If you need more control or need to support older versions of Rust, keep reading.

    Rust 1.0 and up

    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);
    }
    

    This can be fancied up by implementing one of the formatting traits (fmt::Debug, fmt::Display, fmt::LowerHex, fmt::UpperHex, etc.) on a wrapper struct and having a little constructor:

    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>
    }
    

    You can be even fancier and create an extension trait:

    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());
    }
    
    0 讨论(0)
  • 2020-11-28 14:59

    Since the accepted answer doesn't work on Rust 1.0 stable, here's my attempt. Should be allocationless and thus reasonably fast. This is basically a formatter for [u8], but because of the coherence rules, we must wrap [u8] to a self-defined type ByteBuf(&[u8]) to use it:

    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(())
        }
    }
    

    Usage:

    let buff = [0_u8; 24];
    println!("{:x}", ByteBuf(&buff));
    
    0 讨论(0)
提交回复
热议问题