如何使用nom解析一段u16输入?

问题描述 投票:1回答:2

给定&[u16]的原始输入流我如何使用nom来解析它,考虑到nom期望&str作为输入?

例如,给出以下数据:

pub const RAW_INPUT: &[u16] = &[102, 111, 111];

我想将其解析为字符串“foo”。

rust nom
2个回答
0
投票

你可以通过几种方式来做这件事。我对modbus一无所知,所以我假设输入看起来像你上面的RAW_INPUT。首先,您可以使用as将u16转换为u8。这将默默地截断大于255的值。另一种更安全的方法是使用std::convert::TryFrom

在某些情况下可能以受控方式失败的简单且安全的类型转换。这是TryInto的倒数。

当您进行可能非常成功但可能还需要特殊处理的类型转换时,这非常有用。例如,没有办法使用i64特征将i32转换为From,因为i64可能包含i32无法表示的值,因此转换将丢失数据。这可以通过将i64截断为i32(基本上给出i64的值模数i32::MAX)或简单地返回i32::MAX或其他方法来处理。 From特性用于完美转换,因此当类型转换可能变坏并让他们决定如何处理时,TryFrom特性会通知程序员。

你可以在Rust Playground上玩一些说明性的代码:

#[cfg(test)]
mod tests {
    use std::convert::TryFrom;
    use std::num::TryFromIntError;
    use std::str;

    pub const RAW_BAD_INPUT: &[u16] = &[102, 111, 111, 300];
    pub const RAW_GOOD_INPUT: &[u16] = &[102, 111, 111];

    /// Converts using `as`. Demonstrates truncation.
    #[test]
    fn test_truncating() {
        let expected = vec![102, 111, 111, 44];  // Note: 44
        let actual = RAW_BAD_INPUT
            .iter()
            .map(|val| *val as u8)
            .collect::<Vec<u8>>();
        assert_eq!(expected, actual);
    }

    /// Demonstrates conversion using `TryFrom` on input with values that
    /// would be truncated
    #[test]
    fn test_try_from_bad() {
        let actual: Vec<Result<u8, TryFromIntError>> =
            RAW_BAD_INPUT.iter().map(|val| u8::try_from(*val)).collect();

        assert_eq!(actual[0].unwrap(), 102u8);
        assert_eq!(actual[1].unwrap(), 111u8);
        assert_eq!(actual[2].unwrap(), 111u8);
        assert!(actual[3].is_err());
    }

    /// Demonstrates conversion using `TryFrom` on input with values
    /// that would not be truncated. Also parses the Vec<u8> as a UTF-8
    /// encoded string
    #[test]
    fn test_try_from_ok() {
        let intermediate: Vec<u8> = RAW_GOOD_INPUT
            .iter()
            .map(|val| u8::try_from(*val).unwrap())
            .collect();
        let actual = match str::from_utf8(&intermediate) {
            Ok(s) => s,
            Err(e) => panic!("Invalid UTF-8: {}", e),
        };
        assert_eq!("foo", actual);
    }
}

使用test_try_from_ok中的代码,您现在应该有一个String,其中包含您要使用nom解析的数据。


0
投票

鉴于:

pub const RAW_INPUT: &[u16] = &[102, 111, 111];

我最后将输入转换为u8

let xs = RAW_INPUT
    .iter()
    .flat_map(|x| x.to_be_bytes().to_vec())
    .collect::<Vec<u8>>();

然后使用nom解析它。

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