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

如何在Rust中对无空格代数表达式进行词元化

无空格表达式的词元解析解决方案

你的核心问题在于原代码依赖split_whitespace()分割输入,仅能处理带空格的表达式。针对无空格场景,我们可以通过正则匹配遍历的方式,逐个提取符合规则的词元,同时兼容带空格的输入。

方案一:分步匹配处理剩余字符串

这种方式逻辑清晰,便于调试,优先匹配数字(避免运算符与数字正负号混淆),再处理括号和运算符:

use regex::Regex;

pub enum Type {
    Number(f64),
    Operation(char),
    Parentheses(char),
}

fn parse_expression(expression: &str) -> Option<Vec<Type>> {
    let mut tokens = Vec::new();
    let mut remaining = expression;

    // 预编译正则规则
    let number_re = Regex::new(r"[-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?").unwrap();
    let op_re = Regex::new(r"[+\-*/]").unwrap();
    let paren_re = Regex::new(r"[()]").unwrap();

    while !remaining.is_empty() {
        // 跳过空白字符,兼容带空格的输入
        remaining = remaining.trim_start();
        if remaining.is_empty() {
            break;
        }

        // 优先匹配数字(包含正负号、小数、科学计数法)
        if let Some(mat) = number_re.find(remaining) {
            let num = mat.as_str().parse().ok()?;
            tokens.push(Type::Number(num));
            remaining = &remaining[mat.end()..];
        }
        // 匹配括号
        else if let Some(mat) = paren_re.find(remaining) {
            let c = mat.as_str().chars().next().unwrap();
            tokens.push(Type::Parentheses(c));
            remaining = &remaining[mat.end()..];
        }
        // 匹配运算符
        else if let Some(mat) = op_re.find(remaining) {
            let c = mat.as_str().chars().next().unwrap();
            tokens.push(Type::Operation(c));
            remaining = &remaining[mat.end()..];
        }
        // 遇到无法识别的字符,返回None
        else {
            return None;
        }
    }

    Some(tokens)
}

方案二:合并正则捕获组(更简洁)

将所有匹配规则合并到一个正则中,通过命名捕获组区分词元类型,利用captures_iter自动遍历所有匹配结果:

use regex::Regex;

pub enum Type {
    Number(f64),
    Operation(char),
    Parentheses(char),
}

fn parse_expression(expression: &str) -> Option<Vec<Type>> {
    let mut tokens = Vec::new();
    // 合并正则,数字捕获组放在最前面以优先匹配
    let combined_re = Regex::new(
        r"(?P<number>[-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?)|(?P<operation>[+\-*/])|(?P<parentheses>[()])"
    ).unwrap();

    for cap in combined_re.captures_iter(expression) {
        if let Some(num_str) = cap.name("number") {
            let num = num_str.as_str().parse().ok()?;
            tokens.push(Type::Number(num));
        } else if let Some(op_str) = cap.name("operation") {
            let c = op_str.as_str().chars().next().unwrap();
            tokens.push(Type::Operation(c));
        } else if let Some(paren_str) = cap.name("parentheses") {
            let c = paren_str.as_str().chars().next().unwrap();
            tokens.push(Type::Parentheses(c));
        }
    }

    Some(tokens)
}

关键注意事项

  1. 正则优先级:数字正则必须放在最前面,否则像-123这样的负号会被错误识别为减号运算符。
  2. 依赖说明:确保在Cargo.toml中添加regex crate依赖:regex = "1.10"
  3. 错误处理:两种方案都保留了原函数的Option返回类型,遇到无法识别的字符时返回None。
  4. 兼容场景:支持带空格/无空格的表达式,同时正确处理科学计数法(如1e3)、正负号数字(如-0.5)等情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 22:35:42