如何使用 nom 解析 Redis RESP 批量字符串?
How to parse the Redis RESP bulk string using nom?
我需要使用 nom 来解析 RESP request/reply。当我来批量字符串时,比如
"\r\nfoobar\r\n"
或
$-1\r\n
首先,我编写函数从数据中提取 len。
named!(signed_digits<&str, (Option<&str>, &str)>,
pair!(
opt!(alt!(tag!("+") | tag!("-"))),
nom::digit
)
);
named!(signed_integer<&str, i64>,
map_res!(recognize!(signed_digits), FromStr::from_str)
);
named!(get_len_in_bulk_string<&str, i64>,
do_parse!(
tag!("$") >>
len: signed_integer >>
tag!("\r\n") >>
(len)
)
);
然后我根据 len:
得到原始字符串
named!(parse_bulk_string<&str, Record>,
map_res!(gen_len_in_bulk_string, |n|{
if n < 0 {
Record::BulkString(None)
} else {
Record::BulkString(Some(take!(n)))
}
})
);
但是我得到一个编译错误:
Record::BulkString(Some(take!(n)))
^ missing tokens in macro arguments
如何根据之前从文本中提取的len得到原始字符串?看来我不能在自己的闭包中使用 take!
。
像 take!
这样的宏需要在第一个位置有一个 "implicit" 参数:要解析的字符串。通常你看不到它,因为当它嵌套在另一个 nom 宏中时,它是隐式传递的。
但是,在这里,您直接 "calling" 它,因此它需要明确的参数。
相反,您可以这样做:
named!(get_bulk_string<&str, &str>,
do_parse!(
tag!("$") >>
len: signed_integer >>
string: take!(len) >>
tag!("\r\n") >>
(string)
)
);
当然,这忽略了 -1
的情况,你可以用一个开关来处理:
named!(get_bulk_string<&str, Option<&str>>,
do_parse!(
tag!("$") >>
string: switch!(signed_integer,
-1 => map!(take!(0), |_| None) |
_ => map!(take!(42), |s| Some(s))
) >>
tag!("\r\n") >>
(string)
)
);
我需要使用 nom 来解析 RESP request/reply。当我来批量字符串时,比如
"\r\nfoobar\r\n"
或
$-1\r\n
首先,我编写函数从数据中提取 len。
named!(signed_digits<&str, (Option<&str>, &str)>,
pair!(
opt!(alt!(tag!("+") | tag!("-"))),
nom::digit
)
);
named!(signed_integer<&str, i64>,
map_res!(recognize!(signed_digits), FromStr::from_str)
);
named!(get_len_in_bulk_string<&str, i64>,
do_parse!(
tag!("$") >>
len: signed_integer >>
tag!("\r\n") >>
(len)
)
);
然后我根据 len:
得到原始字符串named!(parse_bulk_string<&str, Record>,
map_res!(gen_len_in_bulk_string, |n|{
if n < 0 {
Record::BulkString(None)
} else {
Record::BulkString(Some(take!(n)))
}
})
);
但是我得到一个编译错误:
Record::BulkString(Some(take!(n)))
^ missing tokens in macro arguments
如何根据之前从文本中提取的len得到原始字符串?看来我不能在自己的闭包中使用 take!
。
像 take!
这样的宏需要在第一个位置有一个 "implicit" 参数:要解析的字符串。通常你看不到它,因为当它嵌套在另一个 nom 宏中时,它是隐式传递的。
但是,在这里,您直接 "calling" 它,因此它需要明确的参数。
相反,您可以这样做:
named!(get_bulk_string<&str, &str>,
do_parse!(
tag!("$") >>
len: signed_integer >>
string: take!(len) >>
tag!("\r\n") >>
(string)
)
);
当然,这忽略了 -1
的情况,你可以用一个开关来处理:
named!(get_bulk_string<&str, Option<&str>>,
do_parse!(
tag!("$") >>
string: switch!(signed_integer,
-1 => map!(take!(0), |_| None) |
_ => map!(take!(42), |s| Some(s))
) >>
tag!("\r\n") >>
(string)
)
);