parsing - 如何使用 nom 精确匹配一个字节?

标签 parsing rust nom

我想用 nom 恰好匹配一个字母字符 (a-zA-Z)。

我知道我可以使用 take_while! 贪婪地匹配这样的东西:

// match one or more alphabetical characters
pub fn alpha_many(input: &[u8]) -> IResult<&[u8], &[u8]> {
    take_while!(input, |c| {
        (c >= 0x41 && c <= 0x5a) || (c >= 0x61 && c <= 0x7a)
    })
}

但是我找不到如何只匹配一个字节。有 one_of!,但我不能使用闭包,我必须传递整个切片:

// match exactly one alphabetical character
pub fn alpha_one(input: &[u8]) -> IResult<&[u8], u8> {
    one_of!(
        input,
        [
            0x41, 0x42, 0x43,
            // etc until 0x5a and then from 0x61 to 0x7a
            // ...
        ].as_ref()
    )
}

最佳答案

我想到了这个。如果没有人提出更好的解决方案,我明天会将其标记为已接受的答案:

use nom::{self, ErrorKind, IResult, Needed};

/// Alphabetical characters ([RFC5234 appendix B.1])
///
/// [RFC5234 appendix B.1]: https://tools.ietf.org/html/rfc5234#appendix-B.1
///
/// ```no_rust
/// ALPHA          =  %x41-5A / %x61-7A   ; A-Z / a-z
/// ```
pub struct Alpha;

impl Alpha {
    /// Return true if the given byte represents an alphabetical character
    pub fn is_alpha(c: u8) -> bool {
        (c >= 0x41 && c <= 0x5a) || (c >= 0x61 && c <= 0x7a)
    }

    /// Parse one or more alphabetical characters
    pub fn parse_many(input: &[u8]) -> IResult<&[u8], &[u8]> {
        take_while!(input, Self::is_alpha)
    }

    /// Parse one alphabetical character
    pub fn parse_one(input: &[u8]) -> IResult<&[u8], u8> {
        Self::parse_n(input, 1).map(|res| res[0])
    }

    /// Parse n alphabetical characters
    pub fn parse_n(input: &[u8], n: usize) -> IResult<&[u8], &[u8]> {
        Self::parse_m_n(input, n, n)
    }

    /// Parse between m and n alphabetical characters
    pub fn parse_m_n(input: &[u8], m: usize, n: usize) -> IResult<&[u8], &[u8]> {
        if input.len() < m {
            return IResult::Incomplete(Needed::Size(input.len() - m));
        }
        for i in 0..n {
            if !Self::is_alpha(input[i]) {
                // We were supposed to have at least m printable bytes
                if i < m {
                    return IResult::Error(error_position!(ErrorKind::ManyMN, &input[..]));
                } else {
                    return IResult::Done(&input[i..], &input[0..i]);
                }
            }
        }
        return IResult::Done(&input[n..], &input[0..n]);
    }
}

关于parsing - 如何使用 nom 精确匹配一个字节?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48054475/

相关文章:

vb.net - 如何找到最接近给定日期字符串的有效日期?

javascript - 检查行是否已被解析并插入到 mysql 数据库中

rust - 如何使用 nom 吞噬字符串直到分隔符或结尾?

rust - 在标称5.1.2中使用位解析器时找不到正确的类型参数

使用 nom 解析自定义标识符

java - 格式化文件输入

python - 解析几乎是 Python 的语言的最佳方法?

regex - Rob Pikes 正则表达式的惯用 Rust 重写

traits - Option<T> 其中 T 可以是两个不同的特征?

asynchronous - 为什么在 crossbeam_channel::select 旁边调用时 tokio::spawn 有延迟?