web-dev-qa-db-ja.com

16進数でu8スライスを表示

&[u8]を16進表記に変換する必要があります。たとえば、[ A9, 45, FF, 00 ... ]です。

トレイトstd::fmt::UpperHexはスライスには実装されていません(そのため、std::fmt::formatは使用できません)。 Rustにはserialize::hex::ToHex特性があり、&[u8]を16進文字列に変換しますが、個別のバイトで表現する必要があります。

トレイトUpperHex&[u8]に自分で実装できますが、これがどれほど標準的であるかはわかりません。これを行う最も標準的な方法は何ですか?

25
Aleksandr

Rust 1.26.0以降

:x? "16進整数によるデバッグ"フォーマッタを使用できます。

let data = b"hello";
println!("{:x?}", data);
println!("{:X?}", data);
[68, 65, 6c, 6c, 6f]
[68, 65, 6C, 6C, 6F]

これはpretty修飾子と組み合わせることもできます:

let data = b"hello";
println!("{:#x?}", data);
println!("{:#X?}", data);
[
    0x68,
    0x65,
    0x6c,
    0x6c,
    0x6f,
]
[
    0x68,
    0x65,
    0x6C,
    0x6C,
    0x6F,
]

より詳細な制御が必要な場合や、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);
}

これは、フォーマット特性の1つ( 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>
}

さらに洗練されてextensionトレイトを作成できます。

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());
}
49
Shepmaster

受け入れられた回答が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));
_
6
GolDDranks

これにはクレートがあります: hex-slice

例えば:

extern crate hex_slice;
use hex_slice::AsHex;

fn main() {
    let foo = vec![0u32, 1, 2 ,3];
    println!("{:02x}", foo.as_hex());
}
3
Gabriel