1.前言
先bb两句,确实很长时间没有写总结了。主要也是懒,每天下班就不想动了。之所以又开始写文章了,是因为写项目的时候发现之前学过的知识容易遗忘,所以还是把这些知识先记录一下。
2.nom总结
Rust的nom确实是Rust的强于C/C++的主力之一,他的性能非常快,在单线程的情况下(目前还不会多线程)也能做到几千行的文本在几ms内完成,我目前的学习目标是学习多线程,然后用多线程优化这个项目,到时候我再对比多线程和单线程的性能。
这里将nom几个常用的解析方法总结一下以免遗忘。
1.tuple(( ))(input)?;
这是nom最常用的解析方法(除宏外),tuple(( ))作用类似于parse!,是将括号中的内容,按顺序依次解析,其中input是需要被解析的内容。?是Result的语法糖,代表程序默认他为真。tuple中的方法下面会提及,需要注意的是nom返回的是他自己定义的IResult<(),()>类型,返回值就是两个,接收返回值需要进行错误处理(if let ,unwrap_*()或者?等方法 ),注意用 ?需要该函数返回Result类型。代码示例中用的 _ 表示不需要知道对应方法返回的是什么。
//"a"=x~rust"
fn extra_kv(input:&str)->IResult<&str,(&str,&str)>{
let (input,(_,k,_,_,_,v))=tuple((
tag("\""),
key,
take_until("\""),
tag("\""),
tag("="),
key,
)
)(input)?;
//println!("out:{:?}",out);//("\"", "a", "", "\"", "=", "x")
Ok((input,(k,v)))
}
2.separated_list0( ( ),( ) )(input)?
若input函数中是以 "x,y,z" 中间有分隔符的形式存在,即可使用separated_list0()将其按照对应的分割符分开,将数据存放在对应类型的Vec<T>中。
fn parser(s: &str) -> IResult<&str, Vec<&str>> {
separated_list0(tag("|"), tag("abc"))(s)
}
assert_eq!(parser("abc|abc|abc"), Ok(("", vec!["abc", "abc", "abc"])));
3.opt()(input)?
在递归解析一个input中的结构时,有一个值可能存在于该结构中,也可能不存在。若都按照存在或者不存在的方法去解析则会导致解析失败。于是nom提供了opt()方法,该方法返回一个Option<T>枚举型,若解析到该值则返回Some(T),反之返回None。
fn parser(i: &str) -> IResult<&str, Option<&str>> {
opt(alpha1)(i)
}
assert_eq!(parser("abcd;"), Ok((";", Some("abcd"))));
assert_eq!(parser("123;"), Ok(("123;", None)));
4.alt()(input)?
alt()方法的概念有点类似于opt(),只是opt()是无法确定存不存在该值,而alt()是确定该值存在,但无法确定该值的类型,例如:x 可能是i32 也可能是str ,tuple()无法解析未知类型的数据(当然也有例外,take_until就是一个)。所以nom提供了alt()函数。
fn parser(input: &str) -> IResult<&str, &str> {
alt((alpha1, digit1))(input)
};
assert_eq!(parser("abc"), Ok(("", "abc")));
assert_eq!(parser("123456"), Ok(("", "123456")));
目前常用的nom解析方法就是这些,下面是解析单个值的方法(说明一下就好了,就不放代码了)
一、multispace0 解析掉该方法前面所有的空格(包括\r ,\n等)
二、tag( ) 代表单个值,例如:tag(" , ")就代表 , 如果tag( )放在tuple( )内就会被解析掉对应里面的 值,... 反正他就代表一个字符。
三、alph0/1 digit0/1 alpha代表字符,0表示单个字符,1表示字符串,digit代表整数,0/1目前没 发现有啥区别,可能是用的比较少(因为他返回的是&str,我把数据解析成&str干什么)。
fn parser(input: &str) -> IResult<&str, &str> {
alpha1(input)
}
assert_eq!(parser("aB1c"), Ok(("1c", "aB")));
四、take_until( ) 括号内可以是字符也可以是操作符("\r"),顾名思义就是取到该值为止(不包括该 值),若要将括号内的值一并取掉,可在take_until( )后加一个tag( )。take_while( )用法与之相 反,take_while( )是符合括号内的条件就取,但是二者都没有明确的返回类型,需要上下文推 断。
常用的就这些了,不常用的以后遇见了再加上。
实习总结
经过了两个月时间的实习,收获还是很多,主要是太忙,没什么时间去学习新知识,连写个博客的时间都没有。实习两个月明确了自己的定位,就是自己这点知识啥也不是,以为自己每天自律得学习就比多半同龄人强,可惜现实确实比我强的人太多了,自己就是那个最弱的。不过实习公司的老板不错,虽然不是手把手教我,但是也是经常教我一些东西(可能是他自己太忙了)。总的来说,这两个月的实习让我明白了自己与其他人的差距,剩下的一年我会尽力去弥补这个缺陷。