๐ŸŒŽ Eli Heuerโ€™s Blog

Convert from Roman to Hindu-Arabic Numerals with the Rust Standard Library

November 30, 2020

As a way to better learn Rust, I've been challenging myself to write small programs using just the Rust Standard Library. This is one of those programs. It takes a movie or game title containing a Roman numeral as a command-line argument and returns the same title with Hindu-Arabic numerals instead.

Below is the completed Rust program.

use std::env;
use std::collections::HashMap;
use std::convert::TryInto;

fn main() {
    // Check for Roman numerals in command-line arguments
    let args: Vec<String> = env::args().collect();
    let mut arg_step = 1;
    let mut args_to_convert: Vec<i32> = Vec::new();
    // Note: the 0 arg is the command that ran the program
    for arg in &args[1..] {
        let mut roman_numeral = true;
        for character in arg.chars() {
            match character {
                'I' | 'V' | 'X' | 'L' | 'C' | 'D' | 'M' => (),
                _ => roman_numeral = false,
            }
        };
        if roman_numeral == true {
            args_to_convert.push(arg_step)
        };
        arg_step += 1
    };

    // Setup a key/value map for roman numeral values
    let roman_value: HashMap<char, i32> =
        [('I', 1), ('V', 5), ('X', 10), ('L', 50), ('C', 100), ('D', 500), ('M', 1000)]
        .iter().cloned().collect();

    // Convert Roman numerals found in the previous process
    let mut title = args.to_vec();
    for index_number in args_to_convert {
        let arg_number: usize = index_number.try_into().unwrap();
        let arg_string = &title[arg_number];
        let arg_char_vec: Vec<char> = arg_string.chars().collect();
        let mut char_step = 0;
        let mut old_converted_number = 0;
        let mut new_converted_number = 0;
        let mut integer_value = 0;
        for roman_char in arg_char_vec {
            for (key, value) in roman_value.iter() {
                if roman_char == *key {
                    old_converted_number = new_converted_number;
                    new_converted_number = *value;
                }
            }
            if char_step > 0 && new_converted_number > old_converted_number {
                // Special case for the one-less-than strings like "IX" and "IV"
                // Note that with the string "IV", integer_value will be 1
                // going into the second loop, hence: 5 - (2 * 1) -> 5 - 1 -> 4
                integer_value += new_converted_number - 2 * old_converted_number
            } else {
                // Most conversions steps will use this
                integer_value += new_converted_number
            }
            char_step += 1;
        }
        let integer_value_string = integer_value.to_string();
        if integer_value_string == "1" {
            ();
        } else {
            title[arg_number] = integer_value_string;
        }
    }

    // Print the new title
    title.remove(0);
    let mut joined_title = title.join(" ");
    joined_title = joined_title.to_string();
    println!("{}", joined_title);
}

From a UNIX environment, run:

rustc roman-to-hindu-arabic.rs && ./roman-to-hindu-arabic Final Fantasy VII
Final Fantasy 7