gpt4 book ai didi

rust - 具有严格格式的可选字段

转载 作者:行者123 更新时间:2023-11-29 07:54:20 25 4
gpt4 key购买 nike

我正在尝试构建nom 解析器来检查 ID 为 UUID 的 URL

rooms/e19c94cf-53eb-4048-9c94-7ae74ff6d912

我创建了以下内容:

extern crate uuid;
use uuid::Uuid;

named!(room_uuid<&str, Option<Uuid>>,
do_parse!(
tag_s!("rooms") >>
id: opt!(complete!(preceded!(
tag_s!("/"),
map_res!(take_s!(36), FromStr::from_str)
))) >>

(id)
)
);

它几乎可以很好地处理所有情况:

assert_eq!(room_uuid("rooms"), Done("", None));
assert_eq!(room_uuid("rooms/"), Done("/", None));
assert_eq!(room_uuid("rooms/e19c94cf-53eb-4048-9c94-7ae74ff6d912"), Done("", Some(Uuid::parse_str("e19c94cf-53eb-4048-9c94-7ae74ff6d912").unwrap())));

除了 ID 不是有效 UUID 的情况:

assert!(room_uuid("rooms/123").is_err()); # it fails
# room_uuid("rooms/123").to_result() => Ok(None)

据我所知,这是因为 opt! 将内部 Err 转换为 None

我想将 ID 作为可选部分,但如果它存在,它应该是一个有效的 UUID。
不幸的是,我不明白如何将这两者结合起来:可选性和严格格式。

最佳答案

我在过去几周才开始使用 nom,但我找到了一种解决此问题的方法。它并不完全适合宏,但它确实通过一次修改提供了正确的行为。我吞下了 / 而不是在没有给出 UUID 之后让它悬空。

#[macro_use]
extern crate nom;
extern crate uuid;

use std::str::FromStr;
use nom::IResult;
use uuid::Uuid;

fn room_uuid(input: &str) -> IResult<&str, Option<Uuid>> {
// Check that it starts with "rooms"
let res = tag_s!(input, "rooms");
let remaining = match res {
IResult::Incomplete(i) => return IResult::Incomplete(i),
IResult::Error(e) => return IResult::Error(e),
IResult::Done(i, _) => i
};

// If a slash is not present, return early
let optional_slash = opt!(remaining, tag_s!("/"));
let remaining = match optional_slash {
IResult::Error(_) |
IResult::Incomplete(_) => return IResult::Done(remaining, None),
IResult::Done(i, _) => i
};

// If something follows a slash, make sure
// it's a valid UUID
if remaining.len() > 0 {
let res = complete!(remaining, map_res!(take_s!(36), FromStr::from_str));
match res {
IResult::Done(i, o) => IResult::Done(i, Some(o)),
IResult::Error(e) => IResult::Error(e),
IResult::Incomplete(n) => IResult::Incomplete(n)
}
} else {
// This branch allows for "rooms/"
IResult::Done(remaining, None)
}
}

#[test]
fn match_room_plus_uuid() {
use nom::IResult::*;

assert_eq!(room_uuid("rooms"), Done("", None));
assert_eq!(room_uuid("rooms/"), Done("", None));
assert_eq!(room_uuid("rooms/e19c94cf-53eb-4048-9c94-7ae74ff6d912"), Done("", Some(Uuid::parse_str("e19c94cf-53eb-4048-9c94-7ae74ff6d912").unwrap())));
assert!(room_uuid("rooms/123").is_err());
}

关于rust - 具有严格格式的可选字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48774708/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com