Rust - 如何解析 nom 中的 UTF-8 字母字符?
Rust - How to parse UTF-8 alphabetical characters in nom?
我正在尝试解析字母字符的字符序列,包括德语变音符号 (ä ö ü) 和 UTF-8 字符集中的其他字母字符。
这是我首先尝试的解析器:
named!(
parse(&'a str) -> Self,
map!(
alpha1,
|s| Self { chars: s.into() }
)
);
但它只适用于 ASCII 字母字符 (a-zA-Z)。
我试图通过 char
:
执行解析 char
named!(
parse(&str) -> Self,
map!(
take_while1!(nom::AsChar::is_alpha),
|s| Self { chars: s.into() }
)
);
但这甚至不会解析 "hello",而是导致 Incomplete(Size(1))
错误:
如何解析 nom 中的 UTF-8 字母字符?
我的代码片段:
extern crate nom;
#[derive(PartialEq, Debug, Eq, Clone, Hash, Ord, PartialOrd)]
pub struct Word {
chars: String,
}
impl From<&str> for Word {
fn from(s: &str) -> Self {
Self {
chars: s.into(),
}
}
}
use nom::*;
impl Word {
named!(
parse(&str) -> Self,
map!(
take_while1!(nom::AsChar::is_alpha),
|s| Self { chars: s.into() }
)
);
}
#[test]
fn parse_word() {
let words = vec![
"hello",
"Hi",
"aha",
"Mathematik",
"mathematical",
"erfüllen"
];
for word in words {
assert_eq!(Word::parse(word).unwrap().1, Word::from(word));
}
}
当我运行这个测试时,
cargo test parse_word
我得到:
thread panicked at 'called `Result::unwrap()` on an `Err` value: Incomplete(Size(1))', ...
我知道 char
s 已经是用 Rust 编码的 UTF-8(谢天谢地,万能的),但似乎 nom 库的行为并不像我预期的那样。我正在使用 nom 5.1.0
首先nom 5使用函数进行解析,我建议使用这种形式,因为错误消息更好,代码更清晰。
你的要求很奇怪,你可以把完整的输入变成一个字符串:
impl Word {
fn parse(input: &str) -> IResult<&str, Self> {
Ok((
&input[input.len()..],
Self {
chars: input.to_string(),
},
))
}
}
但我猜你的目的是解析一个词,所以这里有一个你可以做什么的例子:
#[derive(PartialEq, Debug, Eq, Clone, Hash, Ord, PartialOrd)]
pub struct Word {
chars: String,
}
impl From<&str> for Word {
fn from(s: &str) -> Self {
Self { chars: s.into() }
}
}
use nom::{character::complete::*, combinator::*, multi::*, sequence::*, IResult};
impl Word {
fn parse(input: &str) -> IResult<&str, Self> {
let (input, word) =
delimited(space0, recognize(many1_count(none_of(" \t"))), space0)(input)?;
Ok((
input,
Self {
chars: word.to_string(),
},
))
}
}
#[test]
fn parse_word() {
let words = vec![
"hello",
" Hi",
"aha ",
" Mathematik ",
" mathematical",
"erfüllen ",
];
for word in words {
assert_eq!(Word::parse(word).unwrap().1, Word::from(word.trim()));
}
}
您也可以制作一个使用 is_alphabetic()
而不是 none_of(" \t")
的自定义函数,但这需要为 nom 制作一个自定义错误,目前我认为这样做非常烦人。
在这个 Github Issue a fellow contributor quickly whipped up a library (nom-unicode
) 上很好地处理这个问题:
use nom_unicode::complete::{alphanumeric1};
impl Word {
named!(
parse(&'a str) -> Self,
map!(
alphanumeric1,
|w| Self::new(w)
)
);
}
我正在尝试解析字母字符的字符序列,包括德语变音符号 (ä ö ü) 和 UTF-8 字符集中的其他字母字符。 这是我首先尝试的解析器:
named!(
parse(&'a str) -> Self,
map!(
alpha1,
|s| Self { chars: s.into() }
)
);
但它只适用于 ASCII 字母字符 (a-zA-Z)。
我试图通过 char
:
char
named!(
parse(&str) -> Self,
map!(
take_while1!(nom::AsChar::is_alpha),
|s| Self { chars: s.into() }
)
);
但这甚至不会解析 "hello",而是导致 Incomplete(Size(1))
错误:
如何解析 nom 中的 UTF-8 字母字符? 我的代码片段:
extern crate nom;
#[derive(PartialEq, Debug, Eq, Clone, Hash, Ord, PartialOrd)]
pub struct Word {
chars: String,
}
impl From<&str> for Word {
fn from(s: &str) -> Self {
Self {
chars: s.into(),
}
}
}
use nom::*;
impl Word {
named!(
parse(&str) -> Self,
map!(
take_while1!(nom::AsChar::is_alpha),
|s| Self { chars: s.into() }
)
);
}
#[test]
fn parse_word() {
let words = vec![
"hello",
"Hi",
"aha",
"Mathematik",
"mathematical",
"erfüllen"
];
for word in words {
assert_eq!(Word::parse(word).unwrap().1, Word::from(word));
}
}
当我运行这个测试时,
cargo test parse_word
我得到:
thread panicked at 'called `Result::unwrap()` on an `Err` value: Incomplete(Size(1))', ...
我知道 char
s 已经是用 Rust 编码的 UTF-8(谢天谢地,万能的),但似乎 nom 库的行为并不像我预期的那样。我正在使用 nom 5.1.0
首先nom 5使用函数进行解析,我建议使用这种形式,因为错误消息更好,代码更清晰。
你的要求很奇怪,你可以把完整的输入变成一个字符串:
impl Word {
fn parse(input: &str) -> IResult<&str, Self> {
Ok((
&input[input.len()..],
Self {
chars: input.to_string(),
},
))
}
}
但我猜你的目的是解析一个词,所以这里有一个你可以做什么的例子:
#[derive(PartialEq, Debug, Eq, Clone, Hash, Ord, PartialOrd)]
pub struct Word {
chars: String,
}
impl From<&str> for Word {
fn from(s: &str) -> Self {
Self { chars: s.into() }
}
}
use nom::{character::complete::*, combinator::*, multi::*, sequence::*, IResult};
impl Word {
fn parse(input: &str) -> IResult<&str, Self> {
let (input, word) =
delimited(space0, recognize(many1_count(none_of(" \t"))), space0)(input)?;
Ok((
input,
Self {
chars: word.to_string(),
},
))
}
}
#[test]
fn parse_word() {
let words = vec![
"hello",
" Hi",
"aha ",
" Mathematik ",
" mathematical",
"erfüllen ",
];
for word in words {
assert_eq!(Word::parse(word).unwrap().1, Word::from(word.trim()));
}
}
您也可以制作一个使用 is_alphabetic()
而不是 none_of(" \t")
的自定义函数,但这需要为 nom 制作一个自定义错误,目前我认为这样做非常烦人。
在这个 Github Issue a fellow contributor quickly whipped up a library (nom-unicode
) 上很好地处理这个问题:
use nom_unicode::complete::{alphanumeric1};
impl Word {
named!(
parse(&'a str) -> Self,
map!(
alphanumeric1,
|w| Self::new(w)
)
);
}