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 39

Preguntas 9

Ordenar por:

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

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+)

calculadora cient铆fica ??

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

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

Mi solucion fue crear una funcion para no repetir codigo use regex::Regex; fn main() { // Regex // (\d+) \s? \\+ \s? (\d+) -> ej: 1 + 14 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 = Regex::new(r"(\d+)\s?\\/\s?(\d+)").unwrap(); // Traer datos del usuario println!("Ingrese la operaci贸n a realizar: "); let mut <u>expression</u> = String::new(); std::io::stdin().read\_line(\&mut <u>expression</u>).unwrap(); //Mupltiplicacion <u>expression</u> = operation(re\_mult, <u>expression</u>, "\*"); //Division <u>expression</u> = operation(re\_div, <u>expression</u>, "/"); //Resta <u>expression</u> = operation(re\_less, <u>expression</u>, "-"); //Suma <u>expression</u> = operation(re\_add, <u>expression</u>, "+"); // Mostrar datos println!("La expresi贸n es: {}", <u>expression</u>); // Mostrar error} pub fn operation(reg: Regex, mut <u>expresion</u>: String, operation: \&str) -> String { if operation.is\_empty() { return "".to\_string(); } loop { // Aplicar Operaciones let cap = reg.captures(<u>expresion</u>.as\_str()); if cap.is\_none() { break; } let cap = cap.unwrap(); let cap\_expression = cap.get(0).unwrap().as\_str(); let left\_value: i32 = cap.get(1).unwrap().as\_str().parse().unwrap(); let right\_value: i32 = cap.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, }; <u>expresion</u> = <u>expresion</u>.replace(cap\_expression, result.to\_string().as\_str()); } return <u>expresion</u>;}
As铆 resolv铆 el reto de la calculadora. Us茅 un concepto de programaci贸n funcional, que consiste en pasar funciones como argumentos de otras funciones, para evitar repetir c贸digo. Aqu铆 va: ```js use regex::Regex; fn multiply(x: i32, y: i32) -> i32 { return x * y; } fn divide(x: i32, y: i32) -> i32 { return x / y; } fn add(x: i32, y: i32) -> i32 { return x + y; } fn subtract(x: i32, y: i32) -> i32 { return x - y; } fn evaluate_expression<F>(expression: String, regex_expression: Regex, operation: F) -> String where F: Fn(i32, i32) -> i32 { let mut evaluated_expression: String = expression; loop { /* Capturo la expresi贸n */ let captures: Option<regex::Captures<'_>> = regex_expression.captures(evaluated_expression.as_str()); /* A continuaci贸n, se va a validar si la captura contiene un None. Si es as铆, es porque no hay m谩s operaciones, y sale del bucle. Si no, vuelve a evaluar la cadena, para buscar operadores y operandos y resolver la operaci贸n. */ if captures.is_none() { return evaluated_expression; } let captures = captures.unwrap(); let captured_expression = captures.get(0).unwrap().as_str(); let left_value: i32 = captures.get(1).unwrap().as_str().parse().unwrap(); let right_value: i32 = captures.get(2).unwrap().as_str().parse().unwrap(); let operated_value: i32 = operation(left_value, right_value); evaluated_expression = evaluated_expression.replace(captured_expression, &operated_value.to_string()); } } fn main() { println!("Bienvenidx a la calculadora cient铆fica."); /* Evaluar una expresi贸n mediante regex. La expresi贸n para la suma ser铆a: (\d+) \s? \+ \s? (\d+)*/ let regex_multiply = Regex::new(r"(\d+)\s?\*\s?(\d+)").unwrap(); let regex_divide = Regex::new(r"(\d+)\s?\/\s?(\d+)").unwrap(); let regex_add = Regex::new(r"(\d+)\s?\+\s?(\d+)").unwrap(); let regex_subtract = Regex::new(r"(\d+)\s?\-\s?(\d+)").unwrap(); /* Traer los datos del usuario. */ println!("Por favor, introduce tu expresi贸n:"); let mut expression = String::new(); std::io::stdin().read_line(&mut expression).unwrap(); /* Evaluar las expresiones */ let mut result: String = evaluate_expression(expression, regex_multiply, multiply); println!("{}", result); result = evaluate_expression(result, regex_divide, divide); println!("{}", result); result = evaluate_expression(result, regex_add, add); println!("{}", result); result = evaluate_expression(result, regex_subtract, subtract); /* Mostrar el resultado */ println!("El resultado es: {}", result) } ```
Despu茅s de investigar (y experimentar) bastante, aqu铆 est谩 mi soluci贸n:use regex::Regex; fn operation(op\_type: \&str, mut <u>expression</u>: String, re: Regex) -> String {聽 聽 loop {聽 聽 聽 聽 let caps = re.captures(<u>expression</u>.as\_str());聽 聽 聽 聽 聽 聽 聽 聽 if caps.is\_none() {聽 聽 聽 聽 聽 聽 break;聽 聽 聽 聽 }聽 聽 聽 聽 聽 聽 聽 聽 let caps = caps.unwrap();聽 聽 聽 聽 聽 聽 聽 聽 let cap\_expression: \&str = caps.get(0).unwrap().as\_str();聽 聽 聽 聽 let mut <u>left\_value</u>: i32 = 0;聽 聽 聽 聽 let right\_value: i32;聽 聽 聽 聽 let mut <u>right\_value\_u32</u>: u32 = 0;聽 聽 聽 聽 聽 聽 聽 聽 if op\_type != "sqrt" {聽 聽 聽 聽 聽 聽 <u>left\_value</u> = caps.get(1).unwrap().as\_str().parse().unwrap();聽 聽 聽 聽 聽 聽 right\_value = caps.get(2).unwrap().as\_str().parse().unwrap();聽 聽 聽 聽 聽 聽 <u>right\_value\_u32</u> = caps.get(2).unwrap().as\_str().parse().unwrap();聽 聽 聽 聽 } else {聽 聽 聽 聽 聽 聽 right\_value = caps.get(1).unwrap().as\_str().parse().unwrap();聽 聽 聽 聽 } 聽 聽 聽 聽 let mut <u>res</u>: i32 = 0;聽 聽 聽 聽 if op\_type == "-" {聽 聽 聽 聽 聽 聽 <u>res</u> = <u>left\_value</u> - right\_value;聽 聽 聽 聽 } else if op\_type == "+" {聽 聽 聽 聽 聽 聽 <u>res</u> = <u>left\_value</u> + right\_value;聽 聽 聽 聽 } else if op\_type == "/" {聽 聽 聽 聽 聽 聽 <u>res</u> = <u>left\_value</u> / right\_value;聽 聽 聽 聽 } else if op\_type == "\*" {聽 聽 聽 聽 聽 聽 <u>res</u> = <u>left\_value</u> \* right\_value;聽 聽 聽 聽 } else if op\_type == "^" {聽 聽 聽 聽 聽 聽 let res\_option = <u>left\_value</u>.checked\_pow(<u>right\_value\_u32</u>);聽 聽 聽 聽 聽 聽 if res\_option.is\_none() {聽 聽 聽 聽 聽 聽 聽 聽 println!("El n煤mero es demasiado grande");聽 聽 聽 聽 聽 聽 聽 聽 break;聽 聽 聽 聽 聽 聽 } else {聽 聽 聽 聽 聽 聽 聽 聽 <u>res</u> = res\_option.unwrap();聽 聽 聽 聽 聽 聽 }聽 聽 聽 聽 } else if op\_type == "sqrt" {聽 聽 聽 聽 聽 聽 <u>res</u> = (right\_value as f32).sqrt() as i32;聽 聽 聽 聽 } 聽 聽 聽 聽 <u>expression</u> = <u>expression</u>.replace(cap\_expression, &<u>res</u>.to\_string()); 聽 聽 }聽 聽 return <u>expression</u>;} fn main() {聽 聽 // Regex 聽 聽 let re\_sqrt: Regex = Regex::new(r"sqrt(\d+(\\.\d+)?)").unwrap();聽 聽 let re\_exp: Regex = Regex::new(r"(\d+)\s?\\^\s?(\d+)").unwrap();聽 聽 let re\_div: Regex = Regex::new(r"(\d+)\s?\\/\s?(\d+)").unwrap();聽 聽 let re\_mult: Regex = Regex::new(r"(\d+)\s?\\\*\s?(\d+)").unwrap();聽 聽 let re\_sub: Regex = Regex::new(r"(\d+)\s?\\-\s?(\d+)").unwrap();聽 聽 let re\_add: Regex = Regex::new(r"(\d+)\s?\\+\s?(\d+)").unwrap(); 聽 聽 // User input 聽 聽 println!("Por favor ingrese su expresi贸n: ");聽 聽 let mut <u>expression</u>: String = String::new();聽 聽 std::io::stdin().read\_line(\&mut <u>expression</u>).unwrap(); 聽 聽 // Operations聽 聽 <u>expression</u> = operation("sqrt", <u>expression</u>, re\_sqrt);聽 聽 <u>expression</u> = operation("^", <u>expression</u>, re\_exp);聽 聽 <u>expression</u> = operation("/", <u>expression</u>, re\_div);聽 聽 <u>expression</u> = operation("\*", <u>expression</u>, re\_mult);聽 聽 <u>expression</u> = operation("-", <u>expression</u>, re\_sub);聽 聽 <u>expression</u> = operation("+", <u>expression</u>, re\_add);聽 聽 聽 聽 // Output the results聽 聽 println!("Resultado: {}", <u>expression</u>);} ```js use regex::Regex; fn operation(op_type: &str, mut expression: String, re: Regex) -> String { loop { let caps = re.captures(expression.as_str()); if caps.is_none() { break; } let caps = caps.unwrap(); let cap_expression: &str = caps.get(0).unwrap().as_str(); let mut left_value: i32 = 0; let right_value: i32; let mut right_value_u32: u32 = 0; if op_type != "sqrt" { left_value = caps.get(1).unwrap().as_str().parse().unwrap(); right_value = caps.get(2).unwrap().as_str().parse().unwrap(); right_value_u32 = caps.get(2).unwrap().as_str().parse().unwrap(); } else { right_value = caps.get(1).unwrap().as_str().parse().unwrap(); } let mut res: i32 = 0; if op_type == "-" { res = left_value - right_value; } else if op_type == "+" { res = left_value + right_value; } else if op_type == "/" { res = left_value / right_value; } else if op_type == "*" { res = left_value * right_value; } else if op_type == "^" { let res_option = left_value.checked_pow(right_value_u32); if res_option.is_none() { println!("El n煤mero es demasiado grande"); break; } else { res = res_option.unwrap(); } } else if op_type == "sqrt" { res = (right_value as f32).sqrt() as i32; } expression = expression.replace(cap_expression, &res.to_string()); } return expression; } fn main() { // Regex let re_sqrt: Regex = Regex::new(r"sqrt(\d+(\.\d+)?)").unwrap(); let re_exp: Regex = Regex::new(r"(\d+)\s?\^\s?(\d+)").unwrap(); let re_div: Regex = Regex::new(r"(\d+)\s?\/\s?(\d+)").unwrap(); let re_mult: Regex = Regex::new(r"(\d+)\s?\*\s?(\d+)").unwrap(); let re_sub: Regex = Regex::new(r"(\d+)\s?\-\s?(\d+)").unwrap(); let re_add: Regex = Regex::new(r"(\d+)\s?\+\s?(\d+)").unwrap(); // User input println!("Por favor ingrese su expresi贸n: "); let mut expression: String = String::new(); std::io::stdin().read_line(&mut expression).unwrap(); // Operations expression = operation("sqrt", expression, re_sqrt); expression = operation("^", expression, re_exp); expression = operation("/", expression, re_div); expression = operation("*", expression, re_mult); expression = operation("-", expression, re_sub); expression = operation("+", expression, re_add); // Output the results println!("Resultado: {}", expression); } ```
```python use regex::Regex; fn main() { println!("Hola Platzi"); 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(); println!("Por favor introduce tu expresion: "); let mut expression: String = String::new(); std::io::stdin().read_line(&mut expression).unwrap(); 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 rigth_value: i32 = caps.get(2).unwrap().as_str().parse().unwrap(); let mult = left_value * rigth_value; expression = expression.replace(cap_expression, &mult.to_string()); } 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 rigth_value: i32 = caps.get(2).unwrap().as_str().parse().unwrap(); let div = left_value / rigth_value; expression = expression.replace(cap_expression, &div.to_string()); } 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 rigth_value: i32 = caps.get(2).unwrap().as_str().parse().unwrap(); let addition = left_value + rigth_value; expression = expression.replace(cap_expression, &addition.to_string()); } loop { 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 rigth_value: i32 = caps.get(2).unwrap().as_str().parse().unwrap(); let subtraction = left_value - rigth_value; expression = expression.replace(cap_expression, &subtraction.to_string()); } println!("Resultado: {}", expression) } ```

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.

Aqu铆 dejo mi ejercicio donde tambi茅n a帽ado soporte para el uso de par茅ntesis, n煤meros negativos y con una implementaci贸n que trata de asegurar el orden correcto de las operaciones. Lo que hice primeramente fue crear una funci贸n auxiliar para generalizar la aplicaci贸n de las operaciones b谩sicas siguiendo el orden correcto: ```js fn get_operation(input: &str) -> (&str, Regex) { let re_add = Regex::new(r"(-?\d+)\s*\+\s*(-?\d+)").unwrap(); // Regex to find addition let re_subs = Regex::new(r"(-?\d+)\s*\-\s*(-?\d+)").unwrap(); // Regex to find substraction let re_mult = Regex::new(r"(-?\d+)\s*\*\s*(-?\d+)").unwrap(); // Regex to find multiplication let re_div = Regex::new(r"(-?\d+)\s*\/\s*(-?\d+)").unwrap(); // Regex to find division let re_void = Regex::new(r"(\d+)").unwrap(); // Arbitrary regex to return if no operation is found // Check which are the first operations we should solve (following the order of operations) if re_mult.is_match(&input) { return ("mult", re_mult); } else if re_div.is_match(&input) { return ("div", re_div); } // For addition and substraction, we need to check which one is closer to the beginning else if re_add.is_match(&input) || re_subs.is_match(&input) { // Check which operation is closer to the beginning let add = re_add.find(&input); let subs = re_subs.find(&input); if add.is_some() && subs.is_some() { let add = add.unwrap(); let subs = subs.unwrap(); if add.start() < subs.start() { return ("add", re_add); } else { return ("subs", re_subs); } } else if add.is_some() { return ("add", re_add); } else { return ("subs", re_subs); } } // If no operation is found, return a value of "none" and a regex that will return the number else { return ("none", re_void); } } ```Esta funci贸n recibe un string y devuelve una tupla con un otro string identificando cu谩l ser铆a la operaci贸n a aplicar primero y la expresi贸n regular para poder detectarla y aplicarla. Adicionalmente, cree otra funci贸n que recibe como par谩metros el string a aplicar la operaci贸n, el tipo de operaci贸n a aplicar y la expresi贸n regular para aplicarla. Y con base en ello nos devuelve el string original, pero con la operaci贸n aplicada, es decir, si por ejemplo tenemos un string de la forma "4\\\*5-2", al pasar por la primera funci贸n nos dir谩 que la operaci贸n a aplicar primero es la multiplicaci贸n, y al pasar por la segunda nos devolver谩 un string de la forma "10-2": ```js fn apply_operation(input: &str, operation: &str, re: Regex) -> String { // Replace the operation with the result of the operation let result = re.replace_all(input, |caps: &regex::Captures| { let a: i32 = caps[1].parse().unwrap(); let b: i32 = caps[2].parse().unwrap(); match operation { "add" => (a + b).to_string(), "subs" => (a - b).to_string(), "mult" => (a * b).to_string(), "div" => (a / b).to_string(), _ => panic!("Invalid operation"), } }); return result.to_string(); } ```El c贸digo aplica algunas cosas que a煤n no se han visto en el curso y que investigue por mi cuenta, pero realmente hace algo muy parecido a lo que se hizo en clase solo que use lo que se conoce como "Closures" (`|caps: \&regex::Captures|` ) los cuales, para los que tengan experiencia en Python, son bastante similares a las funciones lambda; y para los que no, son b谩sicamente funciones que se crean dentro de otra funci贸n. En este caso, la funci贸n toma los caps del input con base en la expresi贸n regular que pasamos como par谩metro, saca de ah铆 los 2 valores a operar (a, b) y realiza la operaci贸n necesaria que tambi茅n pasamos por par谩metro. La tercera y 煤ltima funci贸n auxiliar que cree fue la de resolver par茅ntesis, que b谩sicamente toma cada uno de los par茅ntesis, los resuelve usando las 2 funciones anteriores, y remplaza los par茅ntesis por un 煤nico valor resultado de las operaciones interiores: ```js fn solve_parentheses(input: String) -> String { // Regex to find expressions inside parentheses let re_parentheses = Regex::new(r"\(([^()]*)\)").unwrap(); // New variable to store the modified input let mut new_input: String = input.clone(); // Loop until there are no more parentheses if re_parentheses.is_match(&input) { // Loop through each parentheses and solve it for caps in re_parentheses.captures_iter(&input) { // Save the full expression inside the parentheses let mut operation = caps[1].to_string(); // Loop until there are no more operations inside the parentheses loop { // Get the operation and the regex to solve it let (operation_name, re) = get_operation(&operation); // If there are no more operations, replace the parentheses with the result if operation_name == "none" { // Replace the parentheses with the result new_input = re_parentheses.replace(&new_input, &operation).to_string(); // Exit the loop break; } else { // If there are more operations, solve them let result = apply_operation(&operation, operation_name, re); operation = result.to_string(); } } } } // Return the modified input without parentheses return new_input; } ```Finalmente, la funci贸n main se encarga de recoger el input del usuario, llamar a las funciones necesarias, y finalmente tratar de convertir el valor a un entero, y en caso de que no sea posible, devolver un error: ```js fn main() { // Get user data println!("Enter an operation:"); let mut input = String::new(); // Read user input io::stdin() .read_line(&mut input) .expect("Failed to read line"); // Do parentheses operations first let mut new_input = solve_parentheses(input.clone()); // Loop until there are no more operations loop { let (operation_name, re) = get_operation(&new_input); if operation_name == "none" { break; } let result = apply_operation(&new_input, operation_name, re); new_input = result.to_string(); } // Cast to i32 let new_input: i32 = new_input .trim() .parse() .expect("Invalid operation, please try again"); // Print the result println!("\nResult: {}", new_input); } ```Hay bastantes mejoras que se le pueden hacer al c贸digo, se podr铆a agregar una funci贸n auxiliar extra que realice el loop de todas las operaciones y as铆 se podr铆a usar tanto dentro de la funci贸n para resolver los par茅ntesis, como en el main para evitar escribir el mismo loop en ambos lados. Adem谩s de la expresi贸n regular para detectar los par茅ntesis, modifique las expresiones regulares del resto de operaciones, por una parte, cambiando el `\s? `por `\s` debido a que este permite validar expresiones que tengan m谩s de un espacio entre medias (por ejemplo "1 +5\\\*2"); Y la otra parte de las expresiones que modifique fue cambiar los `-?\d+` por `-?\d+` . Esto ya que a veces, cuando obten铆a n煤meros negativos en las operaciones, no los ten铆a en cuenta, por ejemplo si se le pasaba un string del tipo "-2+5" dar铆a como resultado -7 porque tomar铆a la operaci贸n como "2+5" y luego le aplicaba el negativo. El c贸digo completo lo pueden encontrar aqu铆: <https://github.com/JsNcAr/Platzi/blob/main/Rust/calculadora/src/main.rs> Para los que no tengan mucha experiencia con la programaci贸n, no se asusten si sienten este c贸digo demasiado complicado, en mi caso lo pude hacer debido a que tengo bastante experiencia con otros lenguajes y quer铆a intentar algo similar a lo que har铆a en los lenguajes que domino m谩s, pero si no pudieron lograr el reto o tienen el c贸digo lleno de errores, es normal y no tiene nada malo, todos pasamos por esa 茅poca y el poder hacer c贸digos m谩s sofisticados est谩 limitado 煤nicamente por el tiempo que le dediques a programar.