1

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

例如,给定以下数据:

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

我想把它解析成字符串“foo”。

4

2 回答 2

0

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

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

当您进行可能很容易成功但也可能需要特殊处理的类型转换时,这很有用。例如,无法使用trait将 an 转换i64为 an ,因为 an可能包含 an无法表示的值,因此转换会丢失数据。这可以通过将 截断为 a (基本上给出' 的值取模)或通过简单地返回或通过其他方法来处理。该特征旨在用于完美转换,因此该特征会在类型转换可能出错时通知程序员并让他们决定如何处理它。i32Fromi64i32i64i32i64i32::MAXi32::MAXFromTryFrom

您可以在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

于 2019-04-14T22:47:25.650 回答
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 正常解析它。

于 2019-04-19T19:47:58.100 回答