如何使用 nom 精确匹配一个字节?
How to match exactly one byte using nom?
我想将一个字母字符 (a-zA-Z
) 与 nom 完全匹配。
我知道我可以使用 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]);
}
}
我想将一个字母字符 (a-zA-Z
) 与 nom 完全匹配。
我知道我可以使用 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]);
}
}