You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Rust中使用nom保留外部解析器的LocatedSpan

解决nom+nom_locate解析u{xxx}时保留完整LocatedSpan的问题

核心思路

要同时保留完整的u{xxx}范围和解析出Unicode字符,需要拆分两步处理:

  1. 用recognize捕获整个u{xxx}的LocatedSpan
  2. 在捕获到的span内部,单独解析十六进制数字并转换为Unicode字符

这样既不会丢失完整的位置信息,也能正常处理数字转换。

实现代码示例

use nom::{
    bytes::complete::tag,
    character::complete::hex_digit1,
    combinator::{map, recognize, verify},
    sequence::delimited,
    IResult,
};
use nom_locate::LocatedSpan;

type Span<'a> = LocatedSpan<&'a str>;

/// 解析u{xxx}格式的Unicode转义,返回(完整span, 对应的char)
fn parse_unicode_escape(input: Span) -> IResult<Span, (Span, char)> {
    // 第一步:用recognize捕获整个u{xxx}的完整span
    let recognize_escape = recognize(
        delimited(
            tag("u{"),
            // 验证十六进制数字长度在1-6之间
            verify(hex_digit1, |s: &str| s.len() >= 1 && s.len() <= 6),
            tag("}"),
        )
    );

    // 第二步:在捕获的span内部解析数字并转成char
    map(recognize_escape, |full_span: Span| {
        // 提取中间的十六进制数字部分(跳过"u{"和"}")
        let digits = &full_span.fragment()[2..full_span.fragment().len()-1];
        // 转换为u32码点
        let code_point = u32::from_str_radix(digits, 16).unwrap();
        // 转换为char(实际代码建议处理无效码点的错误)
        let ch = char::from_u32(code_point).unwrap();
        (full_span, ch)
    })(input)
}

// 测试示例
fn main() {
    let input = Span::new("u{12a}");
    let (remaining, (span, ch)) = parse_unicode_escape(input).unwrap();
    println!("完整span范围:{}..{}", span.location_offset(), span.location_end_offset());
    println!("解析出的字符:{}", ch); // 输出:ሪ
}

关键细节说明

  • recognize的作用是将内部组合子匹配到的整个输入片段作为Span返回,而不是返回组合子的解析结果,这样就拿到了u{12a}的完整位置信息。
  • 在拿到完整span后,通过字符串切片提取中间的十六进制数字(跳过开头的u{和结尾的}),再转换为Unicode字符。
  • 实际项目中建议替换unwrap()为错误处理逻辑,比如用nom的错误类型返回无效码点或格式错误。

内容的提问来源于stack exchange,提问作者Victor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 21:33:23