rust语言nom库常用接口使用示例2

nom库在数据解析方面很实用,接口丰富,上一篇介绍了一些常用的接口,今天再续前篇,分享一些其他接口,希望大家能够从中受益。

根据目前的打算,关于rust语言nom库,大概会分享6篇,读者只需要阅读一下,自然会明了于心。文章力求语言简洁,言简意赅,不注水。不会像讲经文一样,文绉绉的,造成困惑。

length_data 和 be_u16特别适用于解析二进制数据格式(如网络协议、文件格式)

1. be_u16:解析大端序 16 位无符号整数

be_u16 是一个基础解析器,用于从输入字节流中精确地读取 2 个字节,并将它们解释为一个大端序(Big Endian)的 16 位无符号整数(u16。Recognizes a big endian unsigned 2 bytes integer.
  • 模块路径: nom::number::complete::be_u16
  • 作用: 严格读取两个字节并返回一个 u16 整数。
  • 输入/输出: 接收 &[u8](字节切片),返回 u16

2. length_data:解析长度前缀数据

length_data 是一个解析组合器(Parser Combinator,它是一个“高阶函数”,接收另一个解析器作为参数。它的功能是根据读取到的长度来提取后续的数据
  • 模块路径: nom::bytes::complete::length_data
  • 作用:
    1. 调用其参数解析器(例如 be_u16)来确定数据的长度 N。
    2. 读取接下来的 N 个字节作为内容。
  • 输入/输出: 接收 &[u8],返回 &[u8](一个包含内容的子切片)。
使用示例 Demo:解析一个自定义协议包
我们假设有一个自定义二进制数据包格式:
 
字节偏移长度 (字节)描述
0 2 数据长度 (u16, 大端序)
2 N 实际数据 (N 由前面的长度字段决定)
这是一个使用 be_u16 和 length_data 共同解析此格式的完整示例:
 
准备工作:Cargo.toml
[dependencies]
nom = "7.1.3"
完整代码:src/main.rs
use nom::{
    bytes::complete::length_data,
    number::complete::be_u16,
    IResult,
};

/// 解析自定义数据包的函数
/// 输入是字节切片 &[u8],输出是内容字节切片 &[u8]
fn parse_custom_packet(input: &[u8]) -> IResult<&[u8], &[u8]> {
    // length_data 接收 be_u16 作为参数(长度解析器)
    // 返回一个新的解析器,该解析器用于提取实际的数据内容
    length_data(be_u16)(input)
}

fn main() {
    // 示例输入数据:
    // [0x00, 0x04]  -> 长度字段 (u16 BE),值为 4
    // [0xAA, 0xBB, 0xCC, 0xDD] -> 4 字节的数据内容
    // [0xFF, 0xFF]  -> 剩余的未解析数据
    let data = b"\x00\x04\xAA\xBB\xCC\xDD\xFF\xFF";

    match parse_custom_packet(data) {
        Ok((remaining_input, content_data)) => {
            println!("--- 解析成功 ---");
            println!("原始输入长度: {}", data.len());
            println!("提取到的内容长度: {}", content_data.len());
            
            println!("提取出的内容 (Hex): {:?}", content_data);
            println!("剩余未解析的输入 (Hex): {:?}", remaining_input);
            
            // 可以将内容转换为字符串进行展示(如果内容是有效的UTF-8)
            if let Ok(s) = std::str::from_utf8(content_data) {
                println!("内容转换为字符串: {}", s);
            }
        }
        Err(e) => {
            eprintln!("解析失败错误: {:?}", e);
        }
    }
}
运行输出
--- 解析成功 ---
原始输入长度: 8
提取到的内容长度: 4
提取出的内容 (Hex): [170, 187, 204, 221]
剩余未解析的输入 (Hex): [255, 255]

 

posted @ 2025-12-12 10:42  PKICA  阅读(2)  评论(0)    收藏  举报