Converting Roman Numerals To Decimal

2019-01-01 15:54发布

I have managed to get my code to convert most Roman numerals to its appropriate decimal value. But it doesn't work for some exceptional cases. Example : XCIX = 99 but my code prints 109.

Here is my code.

public static int romanConvert(String roman)
{
    int decimal = 0;

    String romanNumeral = roman.toUpperCase();
    for(int x = 0;x<romanNumeral.length();x++)
    {
        char convertToDecimal = roman.charAt(x);

        switch (convertToDecimal)
        {
        case 'M':
            decimal += 1000;
            break;

        case 'D':
            decimal += 500;
            break;

        case 'C':
            decimal += 100;
            break;

        case 'L':
            decimal += 50;
            break;

        case 'X':
            decimal += 10;
            break;

        case 'V':
            decimal += 5;
            break;

        case 'I':
            decimal += 1;
            break;
        }
    }
    if (romanNumeral.contains("IV"))
    {
        decimal-=2;
    }
    if (romanNumeral.contains("IX"))
    {
        decimal-=2;
    }
    if (romanNumeral.contains("XL"))
    {
        decimal-=10;
    }
    if (romanNumeral.contains("XC"))
    {
        decimal-=10;
    }
    if (romanNumeral.contains("CD"))
    {
        decimal-=100;
    }
    if (romanNumeral.contains("CM"))
    {
        decimal-=100;
    }
    return decimal;
}

标签: java
26条回答
深知你不懂我心
2楼-- · 2019-01-01 16:07

what about this conversion. no switch, no case at all...

P.S. : I use this script from a bash shell

import sys

def RomanToNum(r):

    return {
    'I': 1,
    'V': 5,
    'X': 10,
    'L': 50,
    'C': 100,
    'D': 500,
    'M': 1000,
    }[r]

#
#
#

EOF = "<"
Roman = sys.argv[1].upper().strip()+EOF

num = 0
i = 0

while True:

    this = Roman[i]

    if this == EOF:
        break

    n1 = RomanToNum(this)

    next = Roman[i+1]

    if next == EOF:
        n2 = 0
    else:
        n2 = RomanToNum(next)

    if n1 < n2:
        n1 = -1 * n1

    num = num + n1
    i = i + 1

print num
查看更多
其实,你不懂
3楼-- · 2019-01-01 16:07

This should work:

 import java.io.*;
 import java.util.Scanner;

 enum RomanToNumber {
 i(1), v(5), x(10), l(50), c(100); int value;
 RomanToNumber (int p){value = p;}
 int getValue(){return value;}
 }

 public class RomanToInteger {

  public static void main(String[] args){
     RomanToNumber n;

     System.out.println( "Type a valid roman number in lower case" );

     String Str = new String(new Scanner(System.in).nextLine());
     int n1 = 0, theNo = 0, len = Str.length();
     int[] str2No = new int [len];

     for(int i=0; i < len; i++){       
        n = RomanToNumber.valueOf(Str.substring(n1, ++n1));
        str2No[i] = n.getValue();
     }                  

     for(int j = 0; j < (len-1); j++){

        if( str2No[j] >= str2No[j+1] ){ theNo += str2No[j]; }
        else{ theNo -= str2No[j]; }

     }
     System.out.println( theNo += str2No[len-1] );            
     }
  }
查看更多
长期被迫恋爱
4楼-- · 2019-01-01 16:10

Supposing Well-formed Roman numbers:

private static int totalValue(String val)
{
    String aux=val.toUpperCase();
    int sum=0, max=aux.length(), i=0;
    while(i<max)
    {
        if ((i+1)<max && valueOf(aux.charAt(i+1))>valueOf(aux.charAt(i)))
        {
            sum+=valueOf(aux.charAt(i+1)) - valueOf(aux.charAt(i));
            i+=2;
        }
        else
        {
            sum+=valueOf(aux.charAt(i));
            i+=1;
        }
    }
    return sum;
}

private static int valueOf(Character c)
{
    char aux = Character.toUpperCase(c);
    switch(aux)
    {
        case 'I':
            return 1;
        case 'V':
            return 5;
        case 'X':
            return 10;
        case 'L':
            return 50;
        case 'C':
            return 100;
        case 'D':
            return 500;
        case 'M':
            return 1000;
        default:
            return 0;
     }
}
查看更多
妖精总统
5楼-- · 2019-01-01 16:10

Since most of the answers here are in Java, I'm posting the answer in C++ (since I am bored right now and nothing more productive to do :) But please, no downvotes except if code is wrong. Known-issues = will not handle overflow

Code:

#include <unordered_map>
int convert_roman_2_int(string& str)
    {
    int ans = 0;
    if( str.length() == 0 )
        {
        return ans;
        }

    std::unordered_map<char, int> table;
    table['I'] = 1;
    table['V'] = 5;
    table['X'] = 10;
    table['L'] = 50;
    table['C'] = 100;
    table['D'] = 500;
    table['M'] = 1000;

    ans = table[ str[ str.length() - 1 ] ];

    for( int i = str.length() - 2; i >= 0; i--)
        {
        if(table[ str[i] ] < table[ str[i+1] ] )
            {
            ans -= table[ str[i] ];
            }
        else
            {
            ans += table[ str[i] ];
            }
        }

    return ans;
    }

// test code

void run_test_cases_convert_roman_to_int()
    {
    string roman = "VIII";
    int r = convert_roman_2_int(roman);
    cout << roman << " in int is " << r << endl << flush;

    roman = "XX";
    r = convert_roman_2_int(roman);
    cout << roman << " in int is " << r << endl << flush;

    roman = "CDX"; //410
    r = convert_roman_2_int(roman);
    cout << roman << " in int is " << r << endl << flush;

    roman = "MCMXC"; //1990
    r = convert_roman_2_int(roman);
    cout << roman << " in int is " << r << endl << flush;

    roman = "MMVIII"; //2008
    r = convert_roman_2_int(roman);
    cout << roman << " in int is " << r << endl << flush;

    roman = "MDCLXVI"; //1666
    r = convert_roman_2_int(roman);
    cout << roman << " in int is " << r << endl << flush;
    }
查看更多
萌妹纸的霸气范
6楼-- · 2019-01-01 16:11

This is a modest variation of the recursive algorithm suggested by Sahtiel:

public static int toArabic(String number) throws Exception {
    String[] letras = {"M","CM","D","CD","C","XC","L","XL","X", "IX","V","IV","I"};
    int[] valores = {1000,900,500,400,100,90,50,40,10,9,5,4,1};

    // here we can do even more business validations like avoiding sequences like XXXXM
    if (number==null || number.isEmpty()) {
        return 0;
    }
    for(int i=0; i<letras.length; i++) {
        if (number.startsWith(letras[i])) {
            return valores[i] + toArabic(number.substring(letras[i].length()));
        }
    }
    throw new Exception("something bad happened");
}

It uses less than 10 effective lines of code.

查看更多
萌妹纸的霸气范
7楼-- · 2019-01-01 16:14

Solution using tail recursion:

import java.util.LinkedHashMap;

public class RomanNumber {

private final static LinkedHashMap<String, Integer> roman2number = new LinkedHashMap<>(); // preserve key order

static {
    roman2number.put("M", 1000);
    roman2number.put("CM", 900);
    roman2number.put("D", 500);
    roman2number.put("CD", 400);
    roman2number.put("C", 100);
    roman2number.put("XC", 90);
    roman2number.put("L", 50);
    roman2number.put("XL", 40);
    roman2number.put("X", 10);
    roman2number.put("IX", 9);
    roman2number.put("V", 5);
    roman2number.put("IV", 4);
    roman2number.put("I", 1);
}

public final static Integer toDecimal(String roman) {
    for (String key : roman2number.keySet()) {
        if (roman.startsWith(key)) {
            if (roman.equals(key)) {
                return roman2number.get(key);
            }
            return roman2number.get(key) + toDecimal(roman.substring(key.length()));
        }
    }
    return 0;
}
}

Testing:

import junitparams.JUnitParamsRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
import junitparams.Parameters;
import static org.junit.Assert.assertTrue;

@RunWith(JUnitParamsRunner.class)
public class RomanNumberTest {

@Test
@Parameters({ "1|I", "2|II", "3|III", "4|IV", "5|V", "6|VI", "7|VII", "8|VIII", "9|IX", "10|X",
        "11|XI", "12|XII", "13|XIII", "14|XIV", "15|XV", "16|XVI", "17|XVII", "18|XVIII", "19|XIX",
        "20|XX", "50|L", "53|LIII", "57|LVII", "40|XL", "49|XLIX", "59|LIX", "79|LXXIX", "100|C", "90|XC", "99|XCIX",
        "200|CC", "500|D", "499|CDXCIX", "999|CMXCIX", "2999|MMCMXCIX", "3999|MMMCMXCIX"
})
public void forRomanReturnsNumber(int number, String roman) {
    assertTrue(roman + "->" + number, RomanNumber.toDecimal(roman) == (number));
}

}
查看更多
登录 后发表回答