rust - 为什么对 Regex::find 的结果进行匹配会提示期望结构 regex::Match 但找到元组?

标签 rust tuples

我复制了this code from Code Review进入 IntelliJ IDEA 尝试使用它。我有一个与此类似的家庭作业(我需要用 Rust 编写一个 Linux 的 bc 版本),所以我使用此代码仅供引用。

use std::io;
extern crate regex;
#[macro_use]
extern crate lazy_static;

use regex::Regex;

fn main() {
    let tokenizer = Tokenizer::new();

    loop {
        println!("Enter input:");
        let mut input = String::new();
        io::stdin()
            .read_line(&mut input)
            .expect("Failed to read line");
        let tokens = tokenizer.tokenize(&input);
        let stack = shunt(tokens);
        let res = calculate(stack);
        println!("{}", res);
    }
}

#[derive(Debug, PartialEq)]
enum Token {
    Number(i64),
    Plus,
    Sub,
    Mul,
    Div,
    LeftParen,
    RightParen,
}

impl Token {
    /// Returns the precedence of op
    fn precedence(&self) -> usize {
        match *self {
            Token::Plus | Token::Sub => 1,
            Token::Mul | Token::Div => 2,
            _ => 0,
        }
    }
}

struct Tokenizer {
    number: Regex,
}

impl Tokenizer {
    fn new() -> Tokenizer {
        Tokenizer {
            number: Regex::new(r"^[0-9]+").expect("Unable to create the regex"),
        }
    }

    /// Tokenizes the input string into a Vec of Tokens.
    fn tokenize(&self, mut input: &str) -> Vec<Token> {
        let mut res = vec![];

        loop {
            input = input.trim_left();
            if input.is_empty() { break }

            let (token, rest) = match self.number.find(input) {
                Some((_, end)) => {
                    let (num, rest) = input.split_at(end);
                    (Token::Number(num.parse().unwrap()), rest)
                },
                _ => {
                    match input.chars().next() {
                        Some(chr) => {
                            (match chr {
                                '+' => Token::Plus,
                                '-' => Token::Sub,
                                '*' => Token::Mul,
                                '/' => Token::Div,
                                '(' => Token::LeftParen,
                                ')' => Token::RightParen,
                                _ => panic!("Unknown character!"),
                            }, &input[chr.len_utf8()..])
                        }
                        None => panic!("Ran out of input"),
                    }
                }
            };

            res.push(token);
            input = rest;
        }

        res
    }
}

/// Transforms the tokens created by `tokenize` into RPN using the
/// [Shunting-yard algorithm](https://en.wikipedia.org/wiki/Shunting-yard_algorithm)
fn shunt(tokens: Vec<Token>) -> Vec<Token> {
    let mut queue = vec![];
    let mut stack: Vec<Token> = vec![];
    for token in tokens {
        match token {
            Token::Number(_) => queue.push(token),
            Token::Plus | Token::Sub | Token::Mul | Token::Div => {
                while let Some(o) = stack.pop() {
                    if token.precedence() <= o.precedence() {
                        queue.push(o);
                    } else {
                        stack.push(o);
                        break;
                    }
                }
                stack.push(token)
            },
            Token::LeftParen => stack.push(token),
            Token::RightParen => {
                let mut found_paren = false;
                while let Some(op) = stack.pop() {
                    match op {
                        Token::LeftParen => {
                            found_paren = true;
                            break;
                        },
                        _ => queue.push(op),
                    }
                }
                assert!(found_paren)
            },
        }
    }
    while let Some(op) = stack.pop() {
        queue.push(op);
    }
    queue
}

/// Takes a Vec of Tokens converted to RPN by `shunt` and calculates the result
fn calculate(tokens: Vec<Token>) -> i64 {
    let mut stack = vec![];
    for token in tokens {
        match token {
            Token::Number(n) => stack.push(n),
            Token::Plus => {
                let (b, a) = (stack.pop().unwrap(), stack.pop().unwrap());
                stack.push(a + b);
            },
            Token::Sub => {
                let (b, a) = (stack.pop().unwrap(), stack.pop().unwrap());
                stack.push(a - b);
            },
            Token::Mul => {
                let (b, a) = (stack.pop().unwrap(), stack.pop().unwrap());
                stack.push(a * b);
            },
            Token::Div => {
                let (b, a) = (stack.pop().unwrap(), stack.pop().unwrap());
                stack.push(a / b);
            },
            _ => {
                // By the time the token stream gets here, all the LeftParen
                // and RightParen tokens will have been removed by shunt()
                unreachable!();
            },
        }
    }
    stack[0]
}

但是,当我运行它时,它给我这个错误:

error[E0308]: mismatched types
  --> src\main.rs:66:22
   |
66 |                 Some((_, end)) => {
   |                      ^^^^^^^^ expected struct `regex::Match`, found tuple
   |
   = note: expected type `regex::Match<'_>`
              found type `(_, _)`

当我应该使用 token 时,它提示我正在为 Some() 方法使用元组。我不确定要为 token 传递什么,因为元组似乎正在遍历 Token 选项。我如何重写它以使 Some() 方法将元组识别为 Token?我已经为此工作了一天,但我还没有找到任何真正好的解决方案。

最佳答案

您引用的代码已有两年多的历史。值得注意的是,这早于正则表达式 1.0。版本0.1.80 defines Regex::find作为:

fn find(&self, text: &str) -> Option<(usize, usize)>

同时 version 1.0.6 defines it as :

pub fn find<'t>(&self, text: &'t str) -> Option<Match<'t>>

然而,Match定义方法来获取编写代码时假设的起始和结束索引。在这种情况下,由于您只关心结束索引,因此可以调用 Match::end:

let (token, rest) = match self.number.find(input).map(|x| x.end()) {
    Some(end) => {
    // ...

关于rust - 为什么对 Regex::find 的结果进行匹配会提示期望结构 regex::Match 但找到元组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53254221/

相关文章:

windows - 无法在 Windows 上构建 RuSTLess

generics - 特质与通用特质绑定(bind)

rust - 如何在 Any 和 Send Traits 上实现 Sized、Serialize/Deserialize 函数?

python - 使用正则表达式来约束元组列表

python - 如何从数据框 Pandas 制作列表列表?

python - 如果第一个元素是异常,为什么提升元组有效?

iterator - 如何迭代多个范围或迭代器的乘积?

rust - 你如何解决在 Rust 中可变地借用不同的比赛武器的需要?

rust - 检查循环内的字节不起作用

Python - 匹配