我正试图用name5.0解析以下备用字符串
"A-Za-z0-9"或
"A-Z|a-z|0-9"我试过以下几种方法,但都没有用
pub enum Node {
Range(Vec<u8>),
}
fn compound_range(input: &[u8]) -> IResult<&[u8], Node> {
map(
separated_list(
alt((tag("|"), tag(""))),
tuple((take(1usize), tag("-"), take(1usize))),
),
|v: Vec<(&[u8], _, &[u8])>| {
Node::Range(
v.iter()
.map(|(s, _, e)| (s[0]..=e[0]).collect::<Vec<_>>())
.flatten()
.collect(),
)
},
)(input)
}第二版。
fn compound_range(input: &[u8]) -> IResult<&[u8], Node> {
alt((
map(
separated_list(tag("|"), tuple((take(1usize), tag("-"), take(1usize)))),
|v: Vec<(&[u8], _, &[u8])>| {
Node::Range(
v.iter()
.map(|(s, _, e)| (s[0]..=e[0]).collect::<Vec<_>>())
.flatten()
.collect(),
)
},
),
map(
many1(tuple((take(1usize), tag("-"), take(1usize)))),
|v: Vec<(&[u8], _, &[u8])>| {
Node::Range(
v.iter()
.map(|(s, _, e)| (s[0]..=e[0]).collect::<Vec<_>>())
.flatten()
.collect(),
)
},
),
))(input)
}
#[test]
fn parse_compound() {
println!("{:?}", compound_range(b"A-Za-z0-9"));
println!("{:?}", compound_range(b"A-Z|a-z|0-9"));
}我可以让第一个或第二个解析,但永远不能两者兼而有之。有办法表达这一点吗?
发布于 2019-08-16 17:03:36
问题是,nom总是选择它所看到的第一条路径,这在某种程度上是可行的(就像它不需要消耗所有的输入一样)。因此,理想的做法是,在第一个"a-z" (或其他什么)之后将路径拆分为两个可能的路径之一:将|作为分隔符处理,或者不处理。
这是因为nom是一个解析器组合器库,不像regex那样工作,因为regex可以追溯到它需要找到的东西才能工作。
不管怎么说,这样的事情应该有效:
fn compound_range(input: &[u8]) -> IResult<&[u8], Node> {
let single_range = |input| map(
separated_pair(take(1usize), tag("-"), take(1usize)),
|(l, r): (&[u8], &[u8])| (l[0], r[0])
)(input);
map(
opt(
map(
pair(
single_range,
alt((
preceded(tag("|"), separated_nonempty_list(
tag("|"),
single_range,
)),
many0(single_range)
))
),
|(first, rest)| Node::Range(
std::iter::once(first).chain(rest).flat_map(|(l, r)| l..r).collect()
)
),
),
|o| o.unwrap_or_else(|| Node::Range(Vec::new()))
)(input)
}有更好的办法吗?可能吧。考虑到特定的任务,手动实现解析器的那一部分可能是有意义的。是这样的吗?可能吧。(我还没试过)
另外,要记住的是:如果您期望一些其他的东西适合它之后的模式,这可能会消耗太多。
https://stackoverflow.com/questions/57527176
复制相似问题