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

Rust中获取导致指定文本模式匹配失败的首个字符索引的便捷方法

核心结论

标准regex库无法直接实现你的需求,捕获组仅在全匹配成功时生成,也没有内置API返回匹配失败的精准位置,这是因为正则的NFA匹配逻辑为了性能优化,不会记录匹配过程中的最长有效前缀终止位置。


可行方案

方案1:拆分正则为递进匹配段

你可以把原本的完整正则拆分为多个前缀匹配的小正则,逐段匹配并记录当前游标位置,哪一段匹配失败,当前游标就是错误位置。
比如长选项^--(\w+)=(\w+)$可以拆分为:

  • 匹配开头^--:失败则错误位置为0/1
  • 匹配^\w+:失败则错误位置为2
  • 匹配^=:失败则错误位置为2 + 匹配到的key长度
  • 匹配^\w+$:失败则错误位置为2 + key长度 +1
    这种方案不需要完全放弃正则,适合规则简单的场景。

方案2:手写迷你线性解析器(更推荐)

你的场景规则非常简单,仅需要校验短选项/长选项格式,手写线性遍历的解析器代码量很小,且可以完全自定义错误信息和错误位置,灵活度远高于正则。
示例代码如下:

#[derive(Debug)]
enum ParseError {
    /// 错误位置,错误字符,错误描述
    InvalidCharAt(usize, char, &'static str),
    /// 意外结束位置,期望内容
    UnexpectedEnd(usize, &'static str),
}

fn parse_option(s: &str) -> Result<(), ParseError> {
    let mut chars = s.char_indices().peekable();

    // 校验开头必须为-
    match chars.next() {
        Some((0, '-')) => {},
        Some((idx, c)) => return Err(ParseError::InvalidCharAt(idx, c, "选项必须以'-'开头")),
        None => return Err(ParseError::UnexpectedEnd(0, "期望输入选项")),
    }

    match chars.peek() {
        // 长选项逻辑
        Some((_, '-')) => {
            chars.next();
            let mut key_valid = false;
            // 校验key部分
            while let Some((_, c)) = chars.peek() {
                if c.is_alphanumeric() || *c == '_' {
                    key_valid = true;
                    chars.next();
                } else if *c == '=' {
                    break;
                } else {
                    let (idx, bad_c) = chars.next().unwrap();
                    return Err(ParseError::InvalidCharAt(idx, bad_c, "长选项key仅支持字母、数字、下划线,后续需接'='"));
                }
            }
            if !key_valid {
                return Err(ParseError::InvalidCharAt(2, s.chars().nth(2).unwrap(), "--后必须填写长选项key"));
            }
            // 校验=
            match chars.next() {
                Some((_, '=')) => {},
                Some((idx, c)) => return Err(ParseError::InvalidCharAt(idx, c, "长选项key后必须接'='和value")),
                None => return Err(ParseError::UnexpectedEnd(s.len(), "长选项key后缺少'='和value")),
            }
            // 校验value部分
            let mut val_valid = false;
            while let Some((_, c)) = chars.peek() {
                if c.is_alphanumeric() || *c == '_' {
                    val_valid = true;
                    chars.next();
                } else {
                    let (idx, bad_c) = chars.next().unwrap();
                    return Err(ParseError::InvalidCharAt(idx, bad_c, "长选项value仅支持字母、数字、下划线"));
                }
            }
            if !val_valid {
                return Err(ParseError::UnexpectedEnd(s.len(), "'='后必须填写长选项value"));
            }
            Ok(())
        }
        // 短选项逻辑
        Some((_, c)) if c.is_alphanumeric() || *c == '_' => {
            chars.next();
            while let Some((idx, c)) = chars.next() {
                if !c.is_alphanumeric() && c != '_' {
                    return Err(ParseError::InvalidCharAt(idx, c, "短选项仅支持字母、数字、下划线"));
                }
            }
            Ok(())
        }
        Some((idx, c)) => {
            Err(ParseError::InvalidCharAt(*idx, *c, "'-'后需接选项名或第二个'-'"))
        }
        None => {
            Err(ParseError::UnexpectedEnd(1, "'-'后缺少选项名"))
        }
    }
}

拿到ParseError后就可以按照你的需求格式化输出诊断信息,比如输入---abc时会返回InvalidCharAt(2, '-', "--后必须填写长选项key"),直接取错误位置即可生成你示例中的提示。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.10 12:54:01