28|Nom:用Rust写一个Parser解析器
唐刚
你好,我是 Mike。今天我们来一起学习如何用 Rust 写一个 Parser 解析器。
说到解析器,非计算机科班出身的人会一脸懵,这是什么?而计算机科班出身的人会为之色变,曾经熬夜啃“龙书”的痛苦经历浮现眼前。解析器往往跟“编译原理”这个概念一起出现,谈解析器色变完全可以理解。
实际上,解析器也没那么难,并不是所有需要“解析”的地方都与编程语言相关。因此我们可以先把“编译原理”的负担给卸掉。在开发过程中,其实经常会碰到需要解析的东西,比如自定义配置文件,从网络上下载下来的一些数据文件、服务器日志文件等。这些其实不需要很深的背景知识。更加复杂一点的,比如网络协议的处理等等,这些也远没有达到一门编程语言的难度。
另一方面,虽然我们这门课属于入门级,但是对于未来的职业规划来说,如果你说你能写解析器,那面试官可能会很感兴趣。所以这节课我会从简单的示例入手,让你放下恐惧,迈上“解析”之路。
解析器是什么?
解析器其实很简单,就是把一个字符串或字节串解析成某种类型。对应的,在 Rust 语言里就是把一个字段串解析成一个 Rust 类型。一个 Parser 其实就是一个 Rust 函数。
这个转换过程有很多种方法。
最原始的是完全手撸,一个字符一个字符吞入解析。
对一些简单情况,直接使用 String 类型中的 find、split、replace 等函数就可以。
用正则表达式能够解析大部分种类的文本。
还可以用一些工具或库帮助解析,比如 Lex、Yacc、LalrPop、Nom、Pest 等。
Rust 语言的宏也能用来设计 DSL,能实现对 DSL 文本的解析。
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
- 深入了解
- 翻译
- 解释
- 总结
Rust解析器Nom:掌握解析器库背后的解析器-组合子思想 本文介绍了如何使用Rust编写解析器,重点介绍了Nom库的特点和工作方式。Nom库以解析器组合子的方式进行解析,能够高效地解析各种类型的数据。文章通过示例展示了如何编写一个最简单的解析器,解析坐标和16进制色彩编码。Nom的学习门槛并不高,学完一部分就能应用一部分,并且能够让读者在以后的工作中快速升级,解决以前不敢去解决的问题。此外,文章还提到了Nom库的广泛应用领域,为读者提供了更多深入研究的方向。通过学习Nom等工具,读者能够轻松自如地解决解析器任务,并且能够达到前所未有的生产力水平,完全不输于甚至超过其他编程语言。文章最后提出了思考题,鼓励读者尝试用Nom解析一个简单版本的CSV格式文件,并分享解析的内容。整体来说,本文内容简洁明了,适合读者快速了解Rust解析器Nom的特点和基本用法。
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Rust 语言从入门到实战》,新⼈⾸单¥59
《Rust 语言从入门到实战》,新⼈⾸单¥59
立即购买
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
登录 后留言
全部留言(3)
- 最新
- 精选
- superggn思考题 ``` use nom::{ bytes::complete::is_not, character::complete::{char, line_ending}, combinator::opt, multi::separated_list0, sequence::terminated, IResult, }; use std::{fs, io::Error}; fn read_file(file_path: &str) -> Result<String, Error> { fs::read_to_string(file_path) } // parse_csv => parser fn parse_csv(input: &str) -> IResult<&str, Vec<Vec<&str>>> { println!("input csv file:"); println!("{}", input); // terminated => combinator // line_ending => parser // opt => combinator separated_list0(terminated(line_ending, opt(line_ending)), parse_line)(input) } // parse_line => parser fn parse_line(input: &str) -> IResult<&str, Vec<&str>> { // separated_list0 => a combinator // accepts 2 parser separated_list0(char(','), is_not(",\r\n"))(input) } fn main() -> Result<(), Box<dyn std::error::Error>> { let file_content = read_file("/path/to/my/file.csv")?; match parse_csv(&file_content) { Ok((_, rows)) => { for row in rows { println!("{:?}", row); } } Err(e) => println!("Failed to parse CSV: {:?}", e), } Ok(()) } ```
作者回复: 👍
2024-01-05归属地:北京2 - Promise老师,请问解析器如何优化性能,比如解析器每天需要处理 PB 级别的文本。每个文件 100M并且需要匹配上百种规则。
作者回复: 100M小问题的,一次性读入内存就行。不同的规则的话,可以用 alt https://docs.rs/nom/latest/nom/branch/fn.alt.html ,另外,nom 还支持流解析,边产生边解析。
2023-12-27归属地:北京 - tianyu0901老师,推荐一个SQL解析器
作者回复: https://crates.io/crates/sqlparser
2023-12-27归属地:上海2
收起评论