No tienes acceso a esta clase

隆Contin煤a aprendiendo! 脷nete y comienza a potenciar tu carrera

Creando nuestra calculadora

13/20
Recursos

Es momento de desarrollar tu primera gran aplicaci贸n en Rust. Eres libre de idear y programar una aplicaci贸n de consola como una calculadora o un calendario. Para esto, ten presenta algunos consejos:

Utilizaci贸n de dependencias en Rust

Explora la gran cantidad de dependencias que tiene Rust en su repositorio para encontrar las que necesites para tu app.

Algunas dependencias interesantes:

Recuerda agregar la dependencia en el archivo Cargo.toml para su posterior descarga e importarla con use.

use regex::Regex;

fn main() {
    // ...
}

Cada dependencia tiene su propia documentaci贸n para que sepas c贸mo utilizarla.

Conversiones de datos en Rust

Veamos algunas formas de convertir datos en Rust que te servir谩 de ahora en adelante.

String a entero

Hay varias formas de declarar una variable del tipo String:

let nombre = "123".to_string();

let nombre: String = "123".to_string();

let nombre = String::from("123");

let mut nombre: String = String::new();
nombre = "123".to_string();

Convi茅rtelo a n煤mero entero con parse(), pero teniendo en cuenta de borrar los espacios en blanco con trim() para evitar inconvenientes y capturar los errores con unwrap().

let number: i32 = nombre.trim().parse().unwrap();
println!("{}", number+1);

String vs. &str

Recuerda que el tipo de dato String permite manipular una cadena de texto, mientras que el tipo de dato &str contiene la referencia a un String, pero solo contiene su valor.
Cuando le asignas a una variable un valor con dobles comillas "", las mismas crean un &str, por esto utilizamos to_string() para que retorne el tipo de dato en formato String y poder manipularlo. Y por este mismo motivo necesitas un String para hacer un .trim().parse() y convertir la variable al tipo entero.

Para convertir un String a &str, solo agrega el & (Ampersand) delante del nombre de la variable o con as_str().

let nombre: String = "123".to_string();
let nombre_plano: &str = &nombre;

let nombre: String = "123".to_string();
let nombre_plano: &str = nombre.as_str();

Muchas formas de hacer lo mismo 驴No te parece?

TIP: Por convencion, en Rust, todas las variables y nombres de funciones que declares utilizan snackcase, o sea, un _ para separar las palabras. EJ: my_variable o my_function.


Rust posee una curva de aprendizaje algo m谩s compleja cuando se trata de tipos de datos y conversiones. Como siempre, la pr谩ctica har谩 que puedas comprender cu谩ndo utilizar cada tipo y ser m谩s veloz resolviendo problemas.


Contribuci贸n creada por: Kevin Fiorentino.

Aportes 34

Preguntas 8

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad?

o inicia sesi贸n.

Regex

(\d+)\s?\+\s?(\d+)

Esta es mi solucion, con una funcion para que no se repita tanto el codigo:

use regex::Regex;

fn make_operation(reg: Regex, mut expresion: String, operation: &str) -> String {
    if operation.is_empty() {
        return "".to_string();
    }
    loop {
        //Aplicar operaciones
        let caps = reg.captures(expresion.as_str());

        if caps.is_none() {
            break;
        }
        let caps = caps.unwrap();

        let cap_expresion = caps.get(0).unwrap().as_str();
        let left_value: i32 = caps.get(1).unwrap().as_str().parse().unwrap();
        let right_value: i32 = caps.get(2).unwrap().as_str().parse().unwrap();

        let result = match operation {
            "+" => left_value + right_value,
            "-" => left_value - right_value,
            "*" => left_value * right_value,
            "/" => left_value / right_value,
            _ => 0,
        };

        expresion = expresion.replace(cap_expresion, &result.to_string());
    }
    expresion
}

fn main() {
    //Regex
    let re_add = Regex::new(r"(\d+)\s?\+\s?(\d+)").unwrap();
    let re_less = Regex::new(r"(\d+)\s?\-\s?(\d+)").unwrap();
    let re_mult = Regex::new(r"(\d+)\s?\*\s?(\d+)").unwrap();
    let re_div = Regex::new(r"(\d+)\s?/\s?(\d+)").unwrap();

    //Traer datos del usuario
    println!("Por favor introduce tu expresion");
    let mut expresion = String::new();
    std::io::stdin().read_line(&mut expresion).unwrap();

    //Multiplicacion
    expresion = make_operation(re_mult, expresion, "*");
    //Division
    expresion = make_operation(re_div, expresion, "/");
    //Suma
    expresion = make_operation(re_add, expresion, "+");
    //Resta
    expresion = make_operation(re_less, expresion, "-");

    //Mostrar resultados
    println!("Resultados: {}", expresion);
}

Ac谩 dejo mi repositorio a la calculadora completa 馃槑
.
Cualquier comentario que tengan, o bug que encuentren, estoy atento a escucharlo 馃憖

regex que incluye todas las operaciones aritm茅ticas

(\d+)\s+?(\+|\*|/|\-)\s+?(\d+)

Mi c贸digo repo le agregu茅 enums para controlar de mejor forma las operaciones.

calculadora cient铆fica ??

Quiz谩 para este ejercicio en particular hubiese preferido usar parser combinators, pareciese que el crate nom es bastante popular en la comunidad Rust. Pero para seguir lo indicado en esta clase segu铆 usando expresiones regulares.

En la siguiente soluci贸n podr谩n apreciar un par de cosas:

  • Acceder a las capturas por medio de nombres, en vez de posici贸n, esto es posible al usar expresiones regulares similares a: r"(?P<left>\d+)\s?\+\s?(?P<right>\d+)". Me parece que el c贸digo queda un poco m谩s legible de esta manera, al menos, al momento de acceder a la captura en espec铆fico parece m谩s claro.
  • Uso de funciones auxiliares, de modo que podamos luego desarrollar pruebas unitarias para verificar el correcto funcionamiento de dichas porciones de c贸digo.
  • Uso de tuplas en donde el primer elemento indica el operador y el segundo su expresi贸n regular asociada.
  • Uso de fold para reducir la expresi贸n original

Ac谩 el m贸dulo principal:

use regex::Regex;

fn main() {
    println!("expression: ");
    let mut expression = String::new();
    std::io::stdin().read_line(&mut expression).unwrap();

    println!("Result: {}", reduce_expression(expression))
}

fn reduce_expression(mut expression: String) -> String {
    let re_add = Regex::new(r"(?P<left>\d+)\s?\+\s?(?P<right>\d+)").unwrap();
    let re_sub = Regex::new(r"(?P<left>\d+)\s?\-\s?(?P<right>\d+)").unwrap();
    let re_mult = Regex::new(r"(?P<left>\d+)\s?\*\s?(?P<right>\d+)").unwrap();
    let re_div = Regex::new(r"(?P<left>\d+)\s?/\s?(?P<right>\d+)").unwrap();

    let precedence = [("/", re_div), ("*", re_mult), ("+", re_add), ("-", re_sub)];

    expression = precedence
        .into_iter()
        .fold(expression, |acc, (operator, re)| apply(re, acc, operator));

    expression
}

// apply the given operation
fn apply(re: Regex, mut expression: String, operator: &str) -> String {
    loop {
        let caps = re.captures(expression.as_str());

        if caps.is_none() {
            break;
        }

        let caps = caps.unwrap();
        let cap_expression = caps.get(0).unwrap().as_str();
        let left_value: i32 = caps.name("left").unwrap().as_str().parse().unwrap();
        let right_value: i32 = caps.name("right").unwrap().as_str().parse().unwrap();
        let result = match operator {
            "+" => left_value + right_value,
            "-" => left_value - right_value,
            "*" => left_value * right_value,
            "/" => left_value / right_value,
            _ => 0,
        };

        expression = expression.replace(cap_expression, &result.to_string());
    }

    expression
}

Y sus correspondientes pruebas unitarias, en realidad hice una sola por aquello de la pereza.

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn test_apply() {
        let expression: String = "12/2*4+1*12-32".to_string();

        assert_eq!(reduce_expression(expression), "4");
    }
}

Pienso que un peque帽o cambio en la regex podr铆a aportar m谩s flexibilidad al usuario: en lugar de utilizar el metachar \s? se puede utilizar \s* para que si el usuario ingresa 10 + 20 , igual tome los valores correspondientes

I think Platzi must clarify this exercise because the teacher鈥檚 implementation is wrong.

Aqu铆 dejo mi aporte, todo esta estructurado en un main, en pr贸ximas sesiones lo hare mediante funciones. Le hice una prueba intensiva de escritorio. Les dejo el link del github.

Calculadora

Aqui dejo mi peque帽o aporte:

use regex::Regex;

fn main() {
    println!("Calculadora");

    // Regex
    let re_add = Regex::new(r"(\d+)\s?([\+\-])\s?(\d+)").unwrap();
    let re_mult = Regex::new(r"(\d+)\s?([/\*])\s?(\d+)").unwrap();

    // Traer datos del usuario
    println!("Ingrese una operacion: ");
    let mut expression = String::new();
    std::io::stdin().read_line(&mut expression).unwrap();

    // Multiplicacion y Division
    loop {
        let caps = re_mult.captures(expression.as_str());

        if caps.is_none() {
            break;
        }
        let caps = caps.unwrap();
        let cap_expression = caps.get(0).unwrap().as_str();
        let left_value: i32 = caps.get(1).unwrap().as_str().parse().unwrap();
        let right_value: i32 = caps.get(3).unwrap().as_str().parse().unwrap();
        let sign = caps.get(2).unwrap().as_str();
        
        if sign == "*" {
            let result = left_value * right_value;
            expression = expression.replace(cap_expression, &result.to_string());
        } else if sign == "/" {
            let result = left_value / right_value;
            expression = expression.replace(cap_expression, &result.to_string());
        }
    }

    // Suma y resta
    loop {
        let caps = re_add.captures(expression.as_str());

        if caps.is_none() {
            break;
        }
        let caps = caps.unwrap();
        let cap_expression = caps.get(0).unwrap().as_str();
        let left_value: i32 = caps.get(1).unwrap().as_str().parse().unwrap();
        let right_value: i32 = caps.get(3).unwrap().as_str().parse().unwrap();
        let sign = caps.get(2).unwrap().as_str();

        if sign == "+" {
            let result = left_value + right_value;
            expression = expression.replace(cap_expression, &result.to_string());
        } else if sign == "-" {
            let result = left_value - right_value;
            expression = expression.replace(cap_expression, &result.to_string());
        }
    }

    // Mostrar resultado
    println!("Resultado: {}", expression);
}

Divison

let _re_div=Regex::new(r"(\d+)\s?/\s?(\d+)").unwrap();

les dejo mi codigo fuente,
github

agrup茅 multiplicacion y division porque sino la que iria antes en el c贸digo es la que tendria preferencia en vez de ir en orden de lectura (propiedad asociativa)

creo que agrupar suma y resta no seria necesario porque son conmutativas

use regex::Regex;

fn main() {
    let re_add_sub = Regex::new("(\\d+)\\s?([\\+\\-])\\s?(\\d+)").unwrap();
    let re_mult_div = Regex::new("(\\d+)\\s?([\\*\\/])\\s?(\\d+)").unwrap();

    println!("Introduzca la operaci贸n: ");
    let mut expression = String::new();
    std::io::stdin().read_line(&mut expression).unwrap();
    //multiplication and division
    loop{
        let caps = re_mult_div.captures(&expression);
        if caps.is_none(){
            break;
        }

        let caps = caps.unwrap();

        // let caps_expression = caps.get(0).unwrap().as_str();
        let caps_num1 : i32 = caps.get(1).unwrap().as_str().parse::<i32>().unwrap();
        let caps_num2 : i32 = caps.get(3).unwrap().as_str().parse::<i32>().unwrap();
        let operator = &caps[2];
        let result = match operator {
            "*" => caps_num1 * caps_num2,
            "/" => caps_num1 / caps_num2,
            _ => {
                println!("Operador no v谩lido: {}", operator);
                break;
            }
        };
        expression = expression.replacen(&caps[0], &result.to_string(), 1);
        println!("La suma es: {}", result);
    }

    //add and sub
    loop{
        let caps = re_add_sub.captures(&expression);
        if caps.is_none(){
            break;
        }

        let caps = caps.unwrap();

        // let caps_expression = caps.get(0).unwrap().as_str();
        let caps_num1 : i32 = caps.get(1).unwrap().as_str().parse::<i32>().unwrap();
        let caps_num2 : i32 = caps.get(3).unwrap().as_str().parse::<i32>().unwrap();
        let operator = &caps[2];
        let result = match operator {
            "+" => caps_num1 + caps_num2,
            "-" => caps_num1 - caps_num2,
            _ => {
                println!("Operador no v谩lido: {}", operator);
                break;
            }
        };
        expression = expression.replacen(&caps[0], &result.to_string(), 1);
        println!("La suma es: {}", result);
    }
}

Mi Soluci贸n cambie la expresi贸n regular por 2 la primera evalua multiplicaci贸n y divisi贸n y la segunda suma y resta.

Luego saca el simbolo para saber que operaci贸n realizar.

use regex::Regex;
use std::io::stdin;

fn operaciones(re: Regex, mut expression: String) -> String {
    loop {
        //multipliction
        let caps = re.captures(expression.as_str());
        if caps.is_none() {
            break;
        }
        let caps = caps.unwrap();
        let cap_expression = caps.get(0).unwrap().as_str();
        let left_value: i32 = caps.get(1).unwrap().as_str().parse().unwrap();
        let symbol: &str = caps.get(2).unwrap().as_str();
        let right_value: i32 = caps.get(3).unwrap().as_str().parse().unwrap();
        let operation = match symbol {
            "*" => left_value * right_value,
            "/" => left_value / right_value,
            "-" => left_value - right_value,
            "+" => left_value + right_value,
            &_ => todo!(),
        };
        expression = expression.replace(cap_expression, &operation.to_string());
    }
    return expression;
}

fn main() {
    //Regex

    let re_expresion_first = Regex::new(r"(\d+)\s?(\*|\/)\s?(\d+)").unwrap();
    let re_expresion_second = Regex::new(r"(\d+)\s?(\+|\-)\s?(\d+)").unwrap();

    // traer datos de usuario
    println!("Por favor introduce tu expresi贸n: ");
    let mut expression = String::new();
    stdin().read_line(&mut expression).unwrap();

    //aplicar operaciones
    expression = operaciones(re_expresion_first, expression);
    expression = operaciones(re_expresion_second, expression);

    // mostrar resultados
    println!("Resultado: {}", expression);
}

Muy buena la clase, lo que si puedo recomendar es que deben explicar de manera mas detallada para los principiantes que el loop simpre va a iterar sobre las dos primeros operandos de la variable expression. Es decir, si yo como usuario introduzco A+B+C la primera vez que itere el programa este me va a reconocer solo A+B, luego reemplaza A+B por el resultado de esta suma en la variable expression. En la segunda iteracion tenemos que expression = resultadoA+B + C, y esta seria la ultima iteracion del programa ya que en expression no conseguiria mas regex de la forma D + D.

Pero me parece que tiene sus fallas

use regex::Regex;

fn main() {
    println!("Hola Platzi");

    // Regex
    let re_add = Regex::new(r"(\d+)\s?\+\s?(\d+)").unwrap();
    let re_mult = Regex::new(r"(\d+)\s?\*\s?(\d+)").unwrap();
    let re_resta = Regex::new(r"(\d+)\s?\-\s?(\d+)").unwrap();
    let re_div = Regex::new(r"(\d+)\s?\/\s?(\d+)").unwrap();

    // Traer datos del usuario
    println!("Por favor introduce tu expresion: ");
    let mut expression = String::new();
    std::io::stdin().read_line(&mut expression).unwrap();

    // multiplicacion
    loop {
        let caps = re_mult.captures(expression.as_str());

        if caps.is_none() {
            break;
        }

        let caps = caps.unwrap();

        let cap_expression = caps.get(0).unwrap().as_str();
        let left_value : i32 = caps.get(1).unwrap().as_str().parse().unwrap();
        let right_value : i32 = caps.get(2).unwrap().as_str().parse().unwrap();

        let mult = left_value * right_value;

        expression = expression.replace(cap_expression, &mult.to_string());

    }

    //suma
    loop {
        let caps = re_add.captures(expression.as_str());

        if caps.is_none() {
            break;
        }

        let caps = caps.unwrap();

        let cap_expression = caps.get(0).unwrap().as_str();
        let left_value : i32 = caps.get(1).unwrap().as_str().parse().unwrap();
        let right_value : i32 = caps.get(2).unwrap().as_str().parse().unwrap();

        let addition = left_value + right_value;

        expression = expression.replace(cap_expression, &addition.to_string());

    }

        // divisi贸n
        loop {
            let caps = re_div.captures(expression.as_str());
    
            if caps.is_none() {
                break;
            }
    
            let caps = caps.unwrap();
    
            let cap_expression = caps.get(0).unwrap().as_str();
            let left_value : i32 = caps.get(1).unwrap().as_str().parse().unwrap();
            let right_value : i32 = caps.get(2).unwrap().as_str().parse().unwrap();
    
            let div = left_value / right_value;
    
            expression = expression.replace(cap_expression, &div.to_string());
    
        }
    
        //resta
        loop {
            let caps = re_resta.captures(expression.as_str());
    
            if caps.is_none() {
                break;
            }
    
            let caps = caps.unwrap();
    
            let cap_expression = caps.get(0).unwrap().as_str();
            let left_value : i32 = caps.get(1).unwrap().as_str().parse().unwrap();
            let right_value : i32 = caps.get(2).unwrap().as_str().parse().unwrap();
    
            let resta = left_value - right_value;
    
            expression = expression.replace(cap_expression, &resta.to_string());
    
        }
    

    println!("Resultado: {}", expression);

}

Mi soluci贸n, pero espero mejorarla con las funciones.

use::regex::Regex;

fn main() {
    // Regex for matching the input
    let re_div = Regex::new(r"(\d+)\s?/\s?(\d+)").unwrap();
    let re_mul = Regex::new(r"(\d+)\s?\*\s?(\d+)").unwrap();
    let re_add = Regex::new(r"(\d+)\s?\+\s?(\d+)").unwrap();
    let re_sub = Regex::new(r"(\d+)\s?\-\s?(\d+)").unwrap();

    // User input
    println!("Enter an operation to perform: ");

    let mut expression = String::new();
    std::io::stdin().read_line(&mut expression).unwrap();

    // Division 
    loop {
        // Calculate operations
        let caps = re_div.captures(&expression);

        if caps.is_none() {
            break;
        }

        let caps = caps.unwrap();

        let cap_expression = caps.get(0).unwrap().as_str();
        let left_value = caps.get(1).unwrap().as_str().parse::<i32>().unwrap();
        let right_value = caps.get(2).unwrap().as_str().parse::<i32>().unwrap();

        let result = left_value / right_value;

        expression = expression.replace(cap_expression, &result.to_string());
    }
    

    // Multiplication
    loop {
        // Calculate operations
        let caps = re_mul.captures(&expression);

        if caps.is_none() {
            break;
        }

        let caps = caps.unwrap();

        let cap_expression = caps.get(0).unwrap().as_str();
        let left_value = caps.get(1).unwrap().as_str().parse::<i32>().unwrap();
        let right_value = caps.get(2).unwrap().as_str().parse::<i32>().unwrap();

        let result = left_value * right_value;

        expression = expression.replace(cap_expression, &result.to_string());
    }

    // Addition
    loop {
        // Calculate operations
        let caps = re_add.captures(&expression);

        if caps.is_none() {
            break;
        }

        let caps = caps.unwrap();

        let cap_expression = caps.get(0).unwrap().as_str();
        let left_value = caps.get(1).unwrap().as_str().parse::<i32>().unwrap();
        let right_value = caps.get(2).unwrap().as_str().parse::<i32>().unwrap();

        let result = left_value + right_value;

        expression = expression.replace(cap_expression, &result.to_string());
    }

    // Subtraction
    loop {
        // Calculate operations
        let caps = re_sub.captures(&expression);

        if caps.is_none() {
            break;
        }

        let caps = caps.unwrap();

        let cap_expression = caps.get(0).unwrap().as_str();
        let left_value = caps.get(1).unwrap().as_str().parse::<i32>().unwrap();
        let right_value = caps.get(2).unwrap().as_str().parse::<i32>().unwrap();

        let result = left_value - right_value;

        expression = expression.replace(cap_expression, &result.to_string());
    }

    println!("Result: {}", expression);
}```

esta clase me parecio bastante interesante y me hizo pensar en como funciona los lenguajes interpretados, por ejemplo python3. probablemente no funcionan asi pero pues imaginen crear un lenguaje de programacion en base a rust.

les comparto mi aporte:

use regex::Regex;

fn main() {
    // regex
    let re_add: Regex = Regex::new(r"(\d+)\s?([+-])\s?(\d+)").unwrap();
    let re_mul: Regex = Regex::new(r"(\d+)\s?([*/])\s?(\d+)").unwrap();

    // user input
    let mut expression = String::new();
    println!("Enter an expression: ");
    std::io::stdin().read_line(&mut expression).unwrap();

    // validate input
    if !re_add.is_match(&expression) && !re_mul.is_match(&expression) {
        println!("Invalid expression");
        return;
    }

    // multiplication and divition
    loop {
        let captures = re_mul.captures(expression.as_str());
        if captures.is_none() {
            break;
        }
        let captures = captures.unwrap();
        let cap_expression = captures.get(0).unwrap().as_str();
        let left_value = captures.get(1).unwrap().as_str().parse::<i32>().unwrap();
        let operator = captures.get(2).unwrap().as_str();
        let right_value = captures.get(3).unwrap().as_str().parse::<i32>().unwrap();

        let mut result_mul = 0;
        if operator == "*" {
            result_mul = left_value * right_value;
        } else if operator == "/" {
            result_mul = left_value / right_value;
        }

        expression = expression.replace(cap_expression, &result_mul.to_string());
    }

    // addition and subtraction
    loop {
        let captures = re_add.captures(expression.as_str());
        if captures.is_none() {
            break;
        }
        let captures = captures.unwrap();
        let cap_expression = captures.get(0).unwrap().as_str();
        let left_value = captures.get(1).unwrap().as_str().parse::<i32>().unwrap();
        let operator = captures.get(2).unwrap().as_str();
        let right_value = captures.get(3).unwrap().as_str().parse::<i32>().unwrap();

        let mut result_sum = 0;
        if operator == "+" {
            result_sum = left_value + right_value;
        } else if operator == "-" {
            result_sum = left_value - right_value;
        }

        expression = expression.replace(cap_expression, &result_sum.to_string());
    }

    // print result
    println!("Result: {}", expression);
}

Para tener en cuenta los n煤meros negativos en las suma u otra operaci贸n al inicio de la operaci贸n se debe agregar -?
ejemplo (-?\d+)\s?+\s?(\d+)

code

Usando match y una funci贸n para evitar repetir c贸digo

use regex::{Captures, Regex};

fn main() {
    // Traer datos del usuario
    println!("Por favor introduce tu expresion: ");
    let mut expresion = String::new();
    std::io::stdin().read_line(&mut expresion).unwrap();

    expresion = make_math(expresion, "*".to_string());
    expresion = make_math(expresion, "/".to_string());
    expresion = make_math(expresion, "+".to_string());
    expresion = make_math(expresion, "-".to_string());

    // Mostrar resultado
    println!("Resultado: {}", expresion)
}

fn make_math(expresion: String, operator: String) -> String {
    // Regex
    let re_mul = Regex::new(r"(\d+)\s?\*\s?(\d+)").unwrap();
    let re_div = Regex::new(r"(\d+)\s?/\s?(\d+)").unwrap();
    let re_add = Regex::new(r"(\d+)\s?\+\s?(\d+)").unwrap();
    let re_minus = Regex::new(r"(\d+)\s?\-\s?(\d+)").unwrap();

    let mut expresion = expresion;
    loop {
        // Aplicar operaciones
        let caps = match operator.as_str() {
            "*" => re_mul.captures(expresion.as_str()),
            "/" => re_div.captures(expresion.as_str()),
            "+" => re_add.captures(expresion.as_str()),
            "-" => re_minus.captures(expresion.as_str()),
            _ => panic!(),
        };

        // let caps = caps.captures(expresion.as_str());
        if caps.is_none() {
            break;
        }

        let caps = caps.unwrap();

        let cap_expression = caps.get(0).unwrap().as_str();
        let left_value: i32 = caps.get(1).unwrap().as_str().parse().unwrap();
        let right_value: i32 = caps.get(2).unwrap().as_str().parse().unwrap();

        let result = match operator.as_str() {
            "*" => left_value * right_value,
            "/" => left_value / right_value,
            "+" => left_value + right_value,
            "-" => left_value - right_value,
            _ => panic!(),
        };

        expresion = expresion.replace(cap_expression, &(result).to_string());
    }

    return expresion;
}

Llevo mucho tiempo programando en Python y decid铆 que mi primer lenguaje, para aprender, bajo nivel iba a ser Rust. No ha sido f谩cil entender todo y menos tener tratar con los tipos y cosas parecidas al operador &. Pero, aqu铆 est谩 mi ejercicio. Trat茅 de expandirlo un poco m谩s y adicional a las 4 operaciones b谩sicas, tambi茅n soporta potenciaci贸n y agrupaciones con par茅ntesis.

use regex::Regex;

fn math_op(expression: &Regex, mut operation: String, operator: &str) -> String {

    loop {
        let caps = expression.captures(operation.as_str());

        if caps.is_none() {
            break;
        }

        let caps = caps.unwrap();
        let cap_expression = caps.get(0).unwrap().as_str();
        let cap_num_1: f64 = caps.get(1).unwrap().as_str().parse().unwrap();
        let cap_num_2: f64 = caps.get(2).unwrap().as_str().parse().unwrap();

        let result = match operator {

            "+" => cap_num_1 + cap_num_2, 
            "-" => cap_num_1 - cap_num_2,
            "*" => cap_num_1 * cap_num_2,
            "/" => cap_num_1 / cap_num_2,
            "^" =>  if cap_num_2 < 0.0 {cap_num_1/cap_num_2} else {cap_num_1.powi(cap_num_2 as i32)},
            _ => 0.0,
        };

        operation = operation.replace(cap_expression, &result.to_string());

    }

    operation

}


fn main() {

    // Regex

    let re_add = Regex::new(r"(\d+)\s?\+\s?(\d+)").unwrap();
    let re_sub = Regex::new(r"(\d+)\s?\-\s?(\d+)").unwrap();
    let re_mult = Regex::new(r"(\d+)\s?\*\s?(\d+)").unwrap();
    let re_div = Regex::new(r"(\d+)\s?/\s?(\d+)").unwrap();
    let power = Regex::new(r"(\d+)\s?\^\s?(-?\d+)").unwrap();
    let parentesis = Regex::new(r"\(([^()]+)\)").unwrap();
   
 // Traer datos del usuario
    println!("Por favor introduce tu expresion: ");
    let mut expression = String::new();
    std::io::stdin().read_line(&mut expression).unwrap();

    loop {

        let cap_par = parentesis.captures(expression.as_str());
       
        if cap_par.is_none() {
            break;
        }  
        
        let cap_par = cap_par.unwrap();
        let capture = cap_par.get(0).unwrap().as_str();

        println!("Formula entre parentesis {}", capture);


        let mut res = math_op(&power,  String::from(capture).clone(), "^");
        res = math_op(&re_mult,String::from(res).clone(), "*");
        res = math_op(&re_div, String::from(res).clone(), "/");
        res = math_op(&re_add, String::from(res).clone(), "+");
        res = math_op(&re_sub, String::from(res).clone(), "-");

        res = res.replace("(", "");
        res = res.replace(")", "");

        println!("{:?}", res);

        expression = expression.replace(capture, &res.to_string());
        
    }

    expression = math_op(&power, expression.clone(), "^");
    expression = math_op(&re_mult, expression.clone(), "*");
    expression = math_op(&re_div, expression.clone(), "/");
    expression = math_op(&re_add, expression.clone(), "+");
    expression = math_op(&re_sub, expression.clone(), "-");
    
    println!("Resultado: {}", expression)
    // Aplicar Operaciones

}
 

Por ac谩 dejo mi soluci贸n, a煤n no hago funciones aparte, espero esa parte del curso:

use regex::Regex;

fn main() {
    //regex
    let re_mul = Regex::new(r"(\d+)\s?\*\s?(\d+)").unwrap();
    let re_div = Regex::new(r"(\d+)\s?/\s?(\d+)").unwrap();
    let re_add = Regex::new(r"(\d+)\s?\+\s?(\d+)").unwrap();
    let re_sub = Regex::new(r"(\d+)\s?\-\s?(\d+)").unwrap();

    //get user input
    println!("Please, enter your math expression: ");
    let mut expression = String::new();
    std::io::stdin().read_line(&mut expression).unwrap();

    //multiplication
    loop {
        //validate math operations
        let caps = re_mul.captures(expression.as_str());

        if caps.is_none() {
            break;
        }
        let caps = caps.unwrap();

        let cap_expression = caps.get(0).unwrap().as_str();
        let left_value: i32 = caps.get(1).unwrap().as_str().parse().unwrap();
        let right_value: i32 = caps.get(2).unwrap().as_str().parse().unwrap();

        let mul =  left_value * right_value;

        expression = expression.replace(cap_expression, &mul.to_string());
    }

    //division
    loop {
        //validate math operations
        let caps = re_div.captures(expression.as_str());

        if caps.is_none() {
            break;
        }
        let caps = caps.unwrap();

        let cap_expression = caps.get(0).unwrap().as_str();
        let left_value: i32 = caps.get(1).unwrap().as_str().parse().unwrap();
        let right_value: i32 = caps.get(2).unwrap().as_str().parse().unwrap();

        let div =  left_value / right_value;

        expression = expression.replace(cap_expression, &div.to_string());
    }

    //addition
    loop {
        //validate math operations
        let caps = re_add.captures(expression.as_str());

        if caps.is_none() {
            break;
        }
        let caps = caps.unwrap();

        let cap_expression = caps.get(0).unwrap().as_str();
        let left_value: i32 = caps.get(1).unwrap().as_str().parse().unwrap();
        let right_value: i32 = caps.get(2).unwrap().as_str().parse().unwrap();

        let addition =  left_value + right_value;

        expression = expression.replace(cap_expression, &addition.to_string());
    }

    //subtraction
    loop {
        //validate math operations
        let caps = re_sub.captures(expression.as_str());

        if caps.is_none() {
            break;
        }
        let caps = caps.unwrap();

        let cap_expression = caps.get(0).unwrap().as_str();
        let left_value: i32 = caps.get(1).unwrap().as_str().parse().unwrap();
        let right_value: i32 = caps.get(2).unwrap().as_str().parse().unwrap();

        let sub =  left_value - right_value;

        expression = expression.replace(cap_expression, &sub.to_string());
    }
    
    //print result
    println!("Result: {}", expression);
}

Hice la calculadora usando otras funciones para separar las responsabilidades, adem谩s, calcula resta, multiplicaci贸n y divisi贸n. Incluso se puede usar parentesis, pero hay bugs porque falta aplicar la norma de operar de izquierda a derecha.
Posdata: En mi c贸digo se puede usar varios espacios porque al inicio los filtra.
Posdata: Hice uso de struct para estar tipando los objetos que estuve usando, solo aplique lo que se de Ts.
Este es el repositorio.

use std::io::{stdin};
use regex::{Regex, Captures};

struct RegexOperators {
    sum: Regex,
    substract: Regex,
    divide: Regex,
    multiply: Regex,
}

struct Expression {
    equation: String,
    parenthesis_1: String,
    parenthesis_2: String,
    variable_1: i16,
    variable_2: i16,
    symbol: String
}

pub fn exercise_calculator() {
    println!("Digit the equation.");

    let operators = RegexOperators {
        sum: Regex::new(r"(\(?)(\d+)(\+)(\d+)(\)?)").unwrap(), 
        substract: Regex::new(r"(\(?)(\d+)(\-)(\d+)(\)?)").unwrap(), 
        divide: Regex::new(r"(\(?)(\d+)(/)(\d+)(\)?)").unwrap(), 
        multiply: Regex::new(r"(\(?)(\d+)(\*)(\d+)(\)?)").unwrap(), 
    };
    
    let mut expression: String = String::new();
    stdin().read_line(&mut expression).unwrap();

    let expression_no_spaces: String = expression.replace(" ", "");

    let mut answer: String = calculator(expression_no_spaces, operators.divide);
    answer = calculator(answer, operators.multiply);
    answer = calculator(answer, operators.sum);
    answer = calculator(answer, operators.substract);

    println!("The answer is: {answer}");
}

fn destructure_caps (caps: Captures) -> Expression{
    let equation = Expression {
        parenthesis_1: caps.get(1).unwrap().as_str().to_string(),
        parenthesis_2: caps.get(5).unwrap().as_str().to_string(),
        symbol: caps.get(3).unwrap().as_str().to_string(),
        variable_1: caps.get(2).unwrap().as_str().parse().unwrap(),
        variable_2: caps.get(4).unwrap().as_str().parse().unwrap(),
        equation: caps.get(0).unwrap().as_str().to_string(),
    };

    return equation;
}

fn calculate (variable_1: i16, variable_2: i16, symbol: &str) -> i16{
    let result: i16 = match symbol {
        "+" => variable_1 + variable_2,
        "-" => variable_1 - variable_2,
        "*" => variable_1 * variable_2,
        "/" => if variable_2 == 0 {
            0
        } else {
            variable_1 / variable_2
        },
        _ => 0,
    };

    return result;
}

fn get_operation (equation: &Expression, result: i16) -> String {
    let new_operation: String;
    if equation.parenthesis_1 == "(" && equation.parenthesis_2 == ")"{
        new_operation = result.to_string();
    } else {
        new_operation = format!("{}{}{}", equation.parenthesis_1, &result.to_string(), equation.parenthesis_2);
    }
    return new_operation;
}

fn calculator (expression: String, operator: Regex) -> String {
    let mut operation: String = expression.clone();

    loop {
        let caps: Option<Captures> = operator.captures(&operation);
        if caps.is_none() {
            break;
        }
        let caps_unwraped: Captures = caps.unwrap();
        let equation: Expression = destructure_caps(caps_unwraped);
        let result: i16 = calculate(equation.variable_1, equation.variable_2, equation.symbol.as_str());
        let new_operation: String = get_operation(&equation, result);
        
        operation = operation.replace(equation.equation.as_str(), &new_operation);
    }

    return operation;
}

Esta es mi solucion para obtener los valores, pensando en un algo mas legible 馃槃

let caps = re_add.captures(&expresion).unwrap();
    let left_value : i32 = caps[1].parse().unwrap();
    let right_value : i32 = caps[2].parse().unwrap();
    println!("{:?} izq: {}, der: {}", caps, left_value, right_value);

Use una funcion para cumplir con el principio DRY (Don鈥檛 Repeat Yourself), usando ademas un switch (se llama match en Rust) y un enum para controlar el tipo de operacion a realizar

Ademas, aunque no se Regex aun, logre hacer una expresion que pudiera utilizar decimales, pues al haber divisiones es siempre posible que hayan resultados con decimales.

Creo que se puede mejorar el regex y se que posiblemente haya algun que otro error de logica, como en el orden de operaciones en el loop, asi que bienvenidas las recomendaciones en todo sentido

use regex::Regex;

enum TipoOperacion {
    SUMA,
    RESTA,
    MULTIPLICACION,
    DIVISION,
}

fn loop_operaciones(string_regex: Regex, mut expresion: String, tipo_operacion: TipoOperacion) -> String {
    loop {
        // Aplicar Operaciones
        let caps = string_regex.captures(expresion.as_str());

        if caps.is_none() {
            break;
        }

        let caps = caps.unwrap();

        let cap_expresion = caps.get(0).unwrap().as_str();

        // Aqui primero se accede a la posicion 1, se pasa a str, luego se parsea a f32 y un ultimo unwrap
        let left_value: f32 = caps.get(1).unwrap().as_str().parse().unwrap();
        let right_value: f32 = caps.get(2).unwrap().as_str().parse().unwrap();

        println!("{:?} izq: {} der: {}", caps, left_value, right_value); // :? dentro de los corchetes hace que de mas informacion
        println!("{}", expresion);
        let resultado: f32;

        match tipo_operacion {
            TipoOperacion::SUMA => resultado = left_value + right_value,
            TipoOperacion::RESTA => resultado = left_value - right_value,
            TipoOperacion::MULTIPLICACION => resultado = left_value * right_value,
            TipoOperacion::DIVISION => resultado = left_value / right_value,
        }

        expresion = expresion.replace(cap_expresion, &resultado.to_string()); // amperson al principio transforma un String a un str
    }
    return expresion;
}

fn main() {
    // Regex
    // Esta es la regex que me funciono para este caso y que desarrolle sobre la marcha, buscar mejor solucion
    let re_suma = Regex::new(r"(\d+\.?\d*)\s*\+\s*(\d+\.?\d*)").unwrap();
    let re_mult = Regex::new(r"(\d+\.?\d*)\s*\*\s*(\d+\.?\d*)").unwrap();
    let re_resta = Regex::new(r"(\d+\.?\d*)\s*\-\s*(\d+\.?\d*)").unwrap();
    let re_division = Regex::new(r"(\d+\.?\d*)\s*/\s*(\d+\.?\d*)").unwrap();

    // (\d+) \s? \+ \s? (\d+)
    /*
    Regex dividida en 5 partes
    Esta regex va a buscar primero un numero de uno o mas digitos
    Luego va a buscar un espacio que seria opcional
    Luego un signo de mas
    Luego otro espacio opcional
    Y por ultimo el otro numero
    Los espacios opcionales son por si el usuario ingresa por ejemplo 1 +2 o 2+ 34 o 3 + 6
    Y pues tambien sirve sin los espacios opcionales 2+5
    */

    // Traer datos del usuario
    let mut expresion = String::new();
    println!("Ingrese la expresion: ");
    std::io::stdin().read_line(&mut expresion).unwrap();
 
    expresion = loop_operaciones(re_mult, expresion, TipoOperacion::MULTIPLICACION);
    expresion = loop_operaciones(re_division, expresion, TipoOperacion::DIVISION);
    expresion = loop_operaciones(re_suma, expresion, TipoOperacion::SUMA);
    expresion = loop_operaciones(re_resta, expresion, TipoOperacion::RESTA);

    // Mostrar resultado
    println!("Resultado: {}", expresion);
}

Asi se desarrolla en la consola:

Ingrese la expresion: 
3*5/6+2-7+3*2+6/7
Captures({0: Some("3*5"), 1: Some("3"), 2: Some("5")}) izq: 3 der: 5
3*5/6+2-7+3*2+6/7

Captures({0: Some("3*2"), 1: Some("3"), 2: Some("2")}) izq: 3 der: 2
15/6+2-7+3*2+6/7

Captures({0: Some("15/6"), 1: Some("15"), 2: Some("6")}) izq: 15 der: 6
15/6+2-7+6+6/7

Captures({0: Some("6/7"), 1: Some("6"), 2: Some("7")}) izq: 6 der: 7
2.5+2-7+6+6/7

Captures({0: Some("2.5+2"), 1: Some("2.5"), 2: Some("2")}) izq: 2.5 der: 2
2.5+2-7+6+0.85714287

Captures({0: Some("7+6"), 1: Some("7"), 2: Some("6")}) izq: 7 der: 6
4.5-7+6+0.85714287

Captures({0: Some("13+0.85714287"), 1: Some("13"), 2: Some("0.85714287")}) izq: 13 der: 0.85714287
4.5-13+0.85714287

Captures({0: Some("4.5-13.857142"), 1: Some("4.5"), 2: Some("13.857142")}) izq: 4.5 der: 13.857142
4.5-13.857142

Resultado: -9.357142

t茅cnicamente es una calculadora pero no cientifica 馃槢

Comparto mi soluci贸n:

<code> 
use regex::Regex;

fn main() {
  // Regex
  let re_add = Regex::new(r"(-?\d+)\s?([\+|\-])\s?(-?\d+)").unwrap();
  let re_prod = Regex::new(r"(-?\d+)\s?([\*|/])\s?(-?\d+)").unwrap();

  // Tomar datos de usuario
  println!("Ingresar expresi贸n: ");
  let mut expression = String::new();
  std::io::stdin().read_line(&mut expression).unwrap();

  // Interpretar expresi贸n y operar
  expression = read(expression, re_prod);
  expression = read(expression, re_add);

  // Mostrar resultados
  println!("Resultado: {}", expression)
}

fn read(mut exp: String, re: Regex) -> String {
  loop {
    let caps = re.captures(exp.as_str());

    if caps.is_none() {
      break;
    }

    let caps = caps.unwrap();

    let caps_exp = caps.get(0).unwrap().as_str();
    let left_value: i32 = caps.get(1).unwrap().as_str().parse().unwrap();
    let operator: &str = caps.get(2).unwrap().as_str();
    let right_value: i32 = caps.get(3).unwrap().as_str().parse().unwrap();

    let res: i32 = operate(left_value, right_value, operator);
    exp = exp.replace(caps_exp, &res.to_string());
  }

  return exp;
}

fn operate(a: i32, b: i32, op: &str) -> i32 {
  match op {
    "+" => a + b,
    "-" => a - b,
    "*" => a * b,
    "/" => a / b,
    _ => 0,
  }
}

Esta es mi soluci贸n al proyecto. Utilizo una sola regex para todas las operaciones matem谩ticas introduciendo un nuevo wildcard. Adem谩s agrego la opci贸n de entender comandos, 鈥渜uit鈥 para salir, 鈥渉elp鈥 para obtener ayuda. Apreciar铆a sus comentarios.

use regex::Regex;
use std::io::{stdin};

fn main() {
    println!("Bienvenido o bienvenida.");
    println!("Introduzca una expresion matematica o pida ayuda con 'help'.");
    loop {
        // Regex definition
        let re_math = Regex::new(r"(\d+)\s?(\+|-|\*|/)\s?(\d+)").unwrap();
        let re_commands = Regex::new(r"(quit|help)").unwrap();

        // Operation Capture
        let mut exp = String::new();
        stdin().read_line(&mut exp).unwrap();
        let exp = exp.trim();

        // Regex Commands
        let commands_caps = re_commands.captures(exp);
        if commands_caps.is_some() {
            let command = commands_caps.unwrap().get(1).unwrap().as_str();
            match command {
                "quit" => break,
                "help" => println!("Introduzca una expresi贸n matem谩tica"),
                _ => println!("Comando no reconocido"),
            }
            continue
        }

        // Regex Match
        let operation_caps = re_math.captures(exp);
        if operation_caps.is_some() {
            let caps = operation_caps.unwrap();
            let elem1: i32 = caps.get(1).unwrap().as_str().parse().unwrap();
            let elem2: i32 = caps.get(3).unwrap().as_str().parse().unwrap();
            let op: &str = caps.get(2).unwrap().as_str();

            match op {
                "+" => println!("=> {}", elem1 + elem2),
                "-" => println!("=> {}", elem1 - elem2),
                "*" => println!("=> {}", elem1 * elem2),
                "/" => println!("=> {}", elem1 / elem2),
                _ => println!("Operaci贸n no reconocida"),
            }

            continue
        }

        println!("Expresi贸n no reconocida. Escriba 'help' para obtener ayuda.");
    }
}

Better TOML, plugin VScode.