Parsing 如何将字符串向量与nom匹配?

Parsing 如何将字符串向量与nom匹配?,parsing,rust,nom,Parsing,Rust,Nom,我正在尝试使用nom创建一个解析器,它将解析一些文本,这可能是许多选项之一。诺姆有alt!因为当值在编译时是已知的,但我的值不会 这是我试图创建自己的解析器的尝试,可以使用Vec进行匹配,我遇到了几个问题 #[macro_use] extern crate nom; use nom::IResult; fn alternative_wrapper<'a>(input: &'a [u8], alternatives: Vec<String>) -> IRe

我正在尝试使用nom创建一个解析器,它将解析一些文本,这可能是许多选项之一。诺姆有alt!因为当值在编译时是已知的,但我的值不会

这是我试图创建自己的解析器的尝试,可以使用Vec进行匹配,我遇到了几个问题

#[macro_use]
extern crate nom;

use nom::IResult;

fn alternative_wrapper<'a>(input: &'a [u8], alternatives: Vec<String>) -> IResult<&'a [u8], &'a [u8]> {
    for alternative in alternatives {
        // tag!("alternative");
        println!("{}", alternative);
    }
    return IResult::Done(input, "test".as_bytes());
}

#[test]
fn test_date() {
    let input = "May";
    named!(alternative, call!(alternative_wrapper));
    let months = vec!(
        "January",
        "February",
        "March",
        "April",
        "May",
        "June",
        "July",
        "August",
        "September",
        "October",
        "November",
        "December"
        ).iter().map(|s| s.to_string()).collect();
    println!("{:?}", alternative("May".as_bytes(), months));
}

如何从函数中创建解析器?以及如何使用现有的解析器,如tag!在alternative_wrapper?

中,我对nom不是很熟悉,并且仍在学习Rust,但我过去使用过解析器组合器

撇开警告不谈,它看起来像是命名的!宏生成一个只接受一个参数的函数,即要分析的字符串

为了满足nom的期望,我想我应该考虑将alternative_包装器编写为一个返回函数的函数。测试结果如下所示:

#[test]
fn test_date() {
    let months = vec!(
        "January",
        "February",
        "March",
        "April",
        "May",
        "June",
        "July",
        "August",
        "September",
        "October",
        "November",
        "December"
        ).iter().map(|s| s.to_string()).collect();
    let parser = generate_alternative_parser(months);
    named!(alternative, call!(parser));
    println!("{:?}", alternative("May".as_bytes()));
}
看起来你需要构造一个alt!从标签表达!s、 但从文件上看,我并不清楚你会怎么做

您的选项列表最终来自哪里


根据你想要完成的事情,可能还有其他一些方法来完成你想要完成的事情。例如,您可能能够解析任何单词,然后根据您的一个选项对其进行验证。

我对nom不是很熟悉,仍在学习Rust,但我过去使用过解析器组合器

撇开警告不谈,它看起来像是命名的!宏生成一个只接受一个参数的函数,即要分析的字符串

为了满足nom的期望,我想我应该考虑将alternative_包装器编写为一个返回函数的函数。测试结果如下所示:

#[test]
fn test_date() {
    let months = vec!(
        "January",
        "February",
        "March",
        "April",
        "May",
        "June",
        "July",
        "August",
        "September",
        "October",
        "November",
        "December"
        ).iter().map(|s| s.to_string()).collect();
    let parser = generate_alternative_parser(months);
    named!(alternative, call!(parser));
    println!("{:?}", alternative("May".as_bytes()));
}
看起来你需要构造一个alt!从标签表达!s、 但从文件上看,我并不清楚你会怎么做

您的选项列表最终来自哪里


根据你想要完成的事情,可能还有其他一些方法来完成你想要完成的事情。例如,您可能能够解析任何单词,然后根据其中一个选项对其进行验证。

从错误开始,第一个错误是由于命名!只接受一个参数,即输入字符串。命名!将为您声明一个函数,在本例中使用签名fn&[u8]>IResult。任何其他参数都没有神奇之处,所以尝试将月向量作为第二个参数传递是行不通的。有一个命名的变体!叫阿格斯!它可以用来声明具有更多参数的函数,而不仅仅是应该进行排序的输入

第二个错误类似,但相反。您正在通过call!仅使用输入而不使用向量调用替代_包装器!。电话!宏实际上可以传递参数,但必须显式传递,即调用!我的朋友,蒙兹

在整理出错误的原因后,您将询问如何创建解析器。实际上,alternative_wrapper已经是一个通过签名的nom解析器了,但是由于您没有通过nom宏声明它,所以没有任何神奇的输入传递发生,这就是为什么标记!当您尝试时,在函数体中不起作用

为了在您自己声明的函数中使用其他组合符,必须手动将输入传递到最外层的宏。在这种情况下,它是唯一的标签!,但是如果你要使用,比如说,不要解析!然后在其中包含多个宏,您只需传递输入即可执行\u parse!。我将在这里提供一个工作版本,其中包含一些额外的调整:

#[macro_use]
extern crate nom;

use std::str;
use nom::IResult;

fn alternative<'a>(input: &'a [u8], alternatives: &Vec<String>) -> IResult<&'a [u8], &'a [u8]> {
    for alternative in alternatives {
        match tag!(input, alternative.as_bytes()) {
            done@IResult::Done(..) => return done,
            _ => () // continue
        }
    }
    IResult::Error(nom::ErrorKind::Tag) // nothing found.
}

fn main() {
    let months: Vec<String> = vec![
        "January", "February", "March", "April", "May", "June", "July",
        "August", "September", "October", "November", "December"
    ].into_iter().map(String::from).collect();

    fn print_res(r: IResult<&[u8],&[u8]>) {
        println!("{:?}", r);
        println!("{:?}\n", str::from_utf8(r.unwrap().1).unwrap());
    }
    print_res(alternative(b"May", &months));
    print_res(alternative(b"August", &months));
    print_res(alternative(b"NoGood", &months));
}

您可以在中查看。

从错误开始,第一个错误是由于命名错误引起的!只接受一个参数,即输入字符串。命名!将为您声明一个函数,在本例中使用签名fn&[u8]>IResult。任何其他参数都没有神奇之处,所以尝试将月向量作为第二个参数传递是行不通的。有一个命名的变体!叫阿格斯!它可以用来声明具有更多参数的函数,而不仅仅是应该进行排序的输入

第二个错误类似,但相反。您正在通过call!仅使用输入而不使用向量调用替代_包装器!。电话!宏实际上可以传递参数,但必须显式传递,即调用!我的朋友,蒙兹

在整理出错误的原因后,您将询问如何创建解析器。实际上,alternative_wrapper已经是一个通过签名的nom解析器了,但是由于您没有通过nom宏声明它,所以没有任何神奇的输入传递发生,这就是为什么标记!当您尝试时,在函数体中不起作用

为了在您自己声明的函数中使用其他组合符,必须手动将输入传递到最外层的宏。在这种情况下,它是唯一的标签!,但是如果你要使用,比如说,不要解析!然后是多个宏w 在这方面,您只需传递输入即可进行解析!。我将在这里提供一个工作版本,其中包含一些额外的调整:

#[macro_use]
extern crate nom;

use std::str;
use nom::IResult;

fn alternative<'a>(input: &'a [u8], alternatives: &Vec<String>) -> IResult<&'a [u8], &'a [u8]> {
    for alternative in alternatives {
        match tag!(input, alternative.as_bytes()) {
            done@IResult::Done(..) => return done,
            _ => () // continue
        }
    }
    IResult::Error(nom::ErrorKind::Tag) // nothing found.
}

fn main() {
    let months: Vec<String> = vec![
        "January", "February", "March", "April", "May", "June", "July",
        "August", "September", "October", "November", "December"
    ].into_iter().map(String::from).collect();

    fn print_res(r: IResult<&[u8],&[u8]>) {
        println!("{:?}", r);
        println!("{:?}\n", str::from_utf8(r.unwrap().1).unwrap());
    }
    print_res(alternative(b"May", &months));
    print_res(alternative(b"August", &months));
    print_res(alternative(b"NoGood", &months));
}

您可以在使用Nom 4的.

中查看它,这里是一个完全通用的输入,无论您的解析器对什么进行操作都有效:

/// Dynamic version of `alt` that takes a slice of strings
fn alternative<T>(input: T, alternatives: &[&'static str]) -> IResult<T, T>
where
    T: InputTake,
    T: Compare<&'static str>,
    T: InputLength,
    T: AtEof,
    T: Clone,
{
    let mut last_err = None;
    for alternative in alternatives {
        let inp = input.clone();
        match tag!(inp, &**alternative) {
            done @ Ok(..) => return done,
            err @ Err(..) => last_err = Some(err), // continue
        }
    }
    last_err.unwrap()
}

/// Usage
named!(test<Span, Span>,
    call!(alternative, &["a", "b", "c"])
);

对于Nom 4,这里是一个完全通用的输入,无论您的解析器对其进行操作:

/// Dynamic version of `alt` that takes a slice of strings
fn alternative<T>(input: T, alternatives: &[&'static str]) -> IResult<T, T>
where
    T: InputTake,
    T: Compare<&'static str>,
    T: InputLength,
    T: AtEof,
    T: Clone,
{
    let mut last_err = None;
    for alternative in alternatives {
        let inp = input.clone();
        match tag!(inp, &**alternative) {
            done @ Ok(..) => return done,
            err @ Err(..) => last_err = Some(err), // continue
        }
    }
    last_err.unwrap()
}

/// Usage
named!(test<Span, Span>,
    call!(alternative, &["a", "b", "c"])
);