我正在 nom 4.2.2 中为基于文本的格式编写解析器,并且我正在使用空格工具来跳过空格。我必须使用自定义解析器,因为这种格式将一些不寻常的字符视为空格。按照该页面上的示例,我使用eat_separator.
如何有效地扩展我的空间解析器以也使用从行注释#到行尾的行注释?这些注释可以出现在字符串之外的任何地方。我总是想扔掉评论的内容:没有什么比预处理器指令更好的了。
出于此问题的目的,CSV样式引用的字符串是一个字符串,其中:
"."Alo""ha"→ Alo"ha."A""" e"无法解析错误输入,例如.这是一个A",然后是垃圾e".我尝试了几件事,其中没有一件完全有效.
我得到的最接近,感谢Mozilla IRC上#nom用户粉红色的一些帮助:
use std::error as stderror; /* Avoids needing nightly to compile */
named!(csv_style_string<&str, String>, map_res!(
terminated!(tag!("\""), not!(peek!(char!('"')))),
csv_string_to_string
));
fn csv_string_to_string(s: &str) -> Result<String, Box<stderror::Error>> {
Ok(s.to_string().replace("\"\"", "\""))
}
Run Code Online (Sandbox Code Playgroud)
这不能正确捕获字符串的结尾.
我也试图使用re_match!宏r#""([^"]|"")*""#,但这总是导致Err::Incomplete(1).
我已经在 nom 中创建了一些重要的解析器,所以我现在对它非常熟悉。到目前为止,我创建的所有解析器总是向解析器提供整个输入切片。
我想创建一个流解析器,我认为这意味着我可以继续将字节输入解析器,直到它完成。我很难找到任何说明这一点的文档或示例,而且我也质疑我对“流式解析器”是什么的假设。
我的问题是:
我正在尝试构建nom解析器来检查 ID 为 UUID 的 URL
rooms/e19c94cf-53eb-4048-9c94-7ae74ff6d912
Run Code Online (Sandbox Code Playgroud)
我创建了以下内容:
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)
)
);
Run Code Online (Sandbox Code Playgroud)
它几乎可以很好地处理所有情况:
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())));
Run Code Online (Sandbox Code Playgroud)
除了 ID 不是有效 UUID 的情况:
assert!(room_uuid("rooms/123").is_err()); # it fails
# room_uuid("rooms/123").to_result() => Ok(None)
Run Code Online (Sandbox Code Playgroud)
据我了解,这是因为opt!将内部转换Err为None.
我想将 ID 作为可选部分,但如果它存在,它应该是一个有效的 UUID。
不幸的是,我不明白如何将这两件事结合起来:可选性和严格格式。
我试图了解Rust宏如何捕获工作,并正在查看nom解析器库。
位置nom / src / bytes.rs声明tag!使用捕获的宏($i:expr, $tag: expr)。但是,在使用的所有地方,tag!它仅使用一个参数,即tag!("+")。例如:NOM-lua52 / op.rs。我已经阅读了有关宏的教程,但是这种结构似乎很特殊。
似乎输入$i是某种隐式的?
我想,以创造一个分裂的空间和逗号日志行Vector的Token第Field并Separator显示在下面的代码.
我的问题是nom似乎没有消耗整个日志行,它留下了最后一部分 - 在这种情况下08:33:58).
main.rs
#![feature(rust_2018_preview)]
#[macro_use] extern crate nom;
#[derive(Debug, PartialEq)]
pub enum Token<'a> {
Separator(&'a [u8]),
Field(&'a [u8]),
}
named!(separator, is_a!(" ,"));
named!(not_sep, is_not!(" ,"));
named!(
token<Token>,
alt_complete!(
separator => { |s| Token::Separator(s) } |
not_sep => { |n| Token::Field(n) }
)
);
named!(sequence<Vec<Token>>, many1!(token));
pub fn scan(input: &[u8]) -> Vec<Token> {
let (_, seq) = sequence(input).unwrap();
seq
}
fn main() {
}
#[cfg(test)]
mod tests {
use …Run Code Online (Sandbox Code Playgroud) 使用nom crate,我正在尝试编写一个解析器,它可以i32从 a 中识别有符号数String,即可以将字符串-42转换为i32表示形式。
到目前为止,我想出了以下内容,但我无法解析负数:
use nom::types::CompleteStr;
use std::str::FromStr;
named!(
i32_parser<CompleteStr, i32>,
map_res!(nom::digit, |CompleteStr(s)| i32::from_str(s))
);
#[test]
fn parse_i32_positive() {
assert_eq!(
i32_parser(CompleteStr::from("42")),
Ok((CompleteStr::from(""), 42))
);
}
#[test]
fn parse_i32_negative() {
assert_eq!(
i32_parser(CompleteStr::from("-42")),
Ok((CompleteStr::from(""), -42))
);
}
Run Code Online (Sandbox Code Playgroud)
我也试过以下,但有一个神秘的编译错误:
use nom::types::CompleteStr;
use std::str::FromStr;
named!(
i32_parser<CompleteStr, i32>,
map_res!(nom::digit, |CompleteStr(s)| i32::from_str(s))
);
#[test]
fn parse_i32_positive() {
assert_eq!(
i32_parser(CompleteStr::from("42")),
Ok((CompleteStr::from(""), 42))
);
}
#[test]
fn parse_i32_negative() {
assert_eq!(
i32_parser(CompleteStr::from("-42")),
Ok((CompleteStr::from(""), -42))
);
}
Run Code Online (Sandbox Code Playgroud)
关于如何修复它的任何建议?或者用 nom 实现这一目标的更简单方法? …
我应该如何使用nom解析类似于 rust 原始字符串的带引号的字符串?我想解析以下内容:
"A standard string"
#"A string containing ["] a quote"#
##"A string containing ["#] a quote and hash "##
Run Code Online (Sandbox Code Playgroud)
我将如何做到这一点,在开始和结束时需要相同数量的“#”符号,同时允许 #'ed 字符串包含未转义的引号和哈希?
使用 nom 解析字符串直到找到字符很容易。如何使用 nom 吞噬字符串直到分隔符或结尾?处理这个问题。
如何使用字符串(多个字符)而不是单个分隔符执行相同的操作?
例如,为了解析abchello,我想解析所有内容,直到hello找到为止。
我有这个使用 nom 4.2.2 的 Rust 程序。(我冒昧地扩展了 nom 解析器功能。)
extern crate failure;
extern crate nom;
use failure::Error;
use std::fs::File;
use std::io::Read;
fn nom_parser(i: &[u8]) -> ::nom::IResult<&[u8], String, u32> {
{ ::nom::lib::std::result::Result::Ok((i, ("foo".to_owned()))) }
}
fn my_parser(buf: &[u8]) -> Result<(&[u8], String), Error> {
Ok((buf, "foo".to_owned()))
}
fn main() -> Result<(), Error> {
let handler = |mut entries: String| { entries.clear() };
loop {
let mut buf = Vec::new();
File::open("/etc/hosts")?.read_to_end(&mut buf)?;
let res = nom_parser(&buf)?.1;
// let res = my_parser(&buf)?.1;
handler(res);
}
} …Run Code Online (Sandbox Code Playgroud)