Rust 语言从入门到实战
唐刚
Rust 语言中文社区联合创始人
5266 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 36 讲
Rust 语言从入门到实战
15
15
1.0x
00:00/00:00
登录|注册

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
立即购买
登录 后留言

全部留言(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
收起评论
显示
设置
留言
3
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部