【问题标题】:Parsing an integer with nom always results in Incomplete用 nom 解析整数总是会导致 Incomplete
【发布时间】:2018-07-10 03:54:44
【问题描述】:

我尝试的一切都会给我Incomplete(Size(1))。我现在最好的猜测是:

named!(my_u64(&str) -> u64,
    map_res!(recognize!(nom::digit), u64::from_str)
);

测试:

#[cfg(test)]
mod test {
    #[test]
    fn my_u64() {
        assert_eq!(Ok(("", 0)), super::my_u64("0"));
    }
}

有时在我的变体中(例如添加complete!),如果我在末尾添加一个字符,我就能够解析它。

我想为此获得一个有效的解析(最终我希望这将允许我为 u64 包装器类型创建一个解析器)但更大的图景我想了解如何自己正确构建解析器。

【问题讨论】:

    标签: rust nom


    【解决方案1】:

    nom 5.1.1 开始,组合解析器的方法从基于宏变为基于函数,nom's author blog 对此进行了更广泛的讨论。

    随着这一变化,另一个随之而来的是 - streamingcomplete 解析器现在驻留在不同的模块中,您需要明确选择所需的解析类型。大多数情况下,模块名称有明显的区别。

    保留旧的宏,但它们严格在流模式下工作。 CompleteStrCompleteByteSlice 之类的类型已不复存在。

    要编写您要求新方式的代码,您可以这样做(notice explicit character::complete in imports

    因为我花了一些时间来掌握它 - 解析器,例如 map_res 返回一个 impl Fn(I) -> IResult<I, O2, E> 这就是为什么有额外的括号 - 来调用那个闭包。

    use std::str;
    use nom::{
        IResult,
        character::complete::{
            digit1
        },
        combinator::{
            recognize,
            map_res
        }
    };
    
    fn my_u64(input : &str) -> IResult<&str, u64> {
        map_res(recognize(digit1), str::parse)(input)
    }
    
    #[cfg(test)]
    mod test {
        use super::*;
        #[test]
        fn test_my_u64() {
            let input = "42";
            let num = my_u64(input);
            assert_eq!(Ok(("", 42u64)), num);
        }
    }
    

    【讨论】:

      【解决方案2】:

      Nom 4 对部分数据的处理比以前的版本更严格,以更好地支持流解析器和自定义输入类型。

      实际上,如果解析器用完输入并且它无法判断它是意味着用完输入,它总是会返回Err::Incomplete。这还可能包含有关解析器期望的确切输入量的信息(在您的情况下,至少多 1 个字节)。

      它使用AtEof trait 确定是否有更多输入。这总是为&amp;str&amp;[u8] 返回false,因为它们不提供任何关于它们是否完整的信息!

      诀窍是更改解析器的输入类型,以明确输入将始终完整 - Nom 为此提供了 CompleteStrCompleteByteSlice 包装器,或者您可以实现自己的输入类型。

      因此,为了让您的解析器按预期工作,它需要看起来像这样:

      named!(my_u64(CompleteStr) -> u64,
          map_res!(recognize!(nom::digit), u64::from_str)
      );
      

      你的测试看起来像这样:

      #[cfg(test)]
      mod test {
          #[test]
          fn my_u64() {
              assert_eq!(Ok((CompleteStr(""), 0)), super::my_u64(CompleteStr("0")));
          }
      }
      

      更多详情请见the announcement post for Nom 4

      【讨论】:

      • 顺便说一句 - 我现在不在一台装有 Rust 编译器的机器上,所以如果代码示例有误,请告诉我,我稍后会修复它们:p
      • 这太好了,谢谢。这是一个非常好的解释,我觉得我已经从向墙上扔东西到坚持到现在真正掌握行为的进展。
      • @spease:没问题,我认为写这个答案也是我第一次完全点击:D
      • 我收到此错误expected &amp;str, found struct nom::types::CompleteStr 任何想法为什么?
      • @Pumphouse a) 你的解析器有正确的签名吗? b) 在尝试传递之前,您是否将输入字符串包装在 CompleteStr 中?
      猜你喜欢
      • 2017-08-05
      • 2022-01-07
      • 1970-01-01
      • 1970-01-01
      • 2014-02-10
      • 1970-01-01
      • 2020-08-13
      • 2021-05-04
      • 1970-01-01
      相关资源
      最近更新 更多