romanos romano para numeros numero enteros decimales convertir conversor conversion arabigos arabes algoritmo java

java - romano - numeros arabes conversor



Conversión de números romanos a decimal (26)

Logré obtener mi código para convertir la mayoría de los números romanos a su valor decimal apropiado. Pero no funciona en algunos casos excepcionales. Ejemplo: XCIX = 99 pero mi código imprime 109 .

Aquí está mi código.

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; }


Imperativo + soluciones recursivas con paso de validación y pruebas en línea

Para evitar cálculos inútiles y asegurarse de que el formato de los números romanos sea el correcto, necesitamos verificar la entrada con una expresión regular.

String regex = "^(M{0,3})(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$";

Solución imperativa

public static int romanToDecimal(String s) { if (s == null || s.isEmpty() || !s.matches("^(M{0,3})(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$")) return -1; final Matcher matcher = Pattern.compile("M|CM|D|CD|C|XC|L|XL|X|IX|V|IV|I").matcher(s); final int[] decimalValues = {1000,900,500,400,100,90,50,40,10,9,5,4,1}; final String[] romanNumerals = {"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"}; int result = 0; while (matcher.find()) for (int i = 0; i < romanNumerals.length; i++) if (romanNumerals[i].equals(matcher.group(0))) result += decimalValues[i]; return result; }

prueba en línea | prueba la versión optimizada con comentarios / explicación en línea

ACTUALIZACIÓN : aquí hay dos propuestas recursivas ingeniosas de este hilo que resolví agregando paso de validación

Solución recursiva 1 ( respuesta original )

public class RomanToDecimalConverter { private static double evaluateNextRomanNumeral(String roman, int pos, double rightNumeral) { if (pos < 0) return 0; char ch = roman.charAt(pos); double value = Math.floor(Math.pow(10, "IXCM".indexOf(ch))) + 5 * Math.floor(Math.pow(10, "VLD".indexOf(ch))); return value * Math.signum(value + 0.5 - rightNumeral) + evaluateNextRomanNumeral(roman, pos - 1, value); } public static int evaluateRomanNumerals(String s) { if (s == null || s.isEmpty() || !s.matches("^(M{0,3})(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$")) return -1; return (int) evaluateNextRomanNumeral(s, s.length() - 1, 0); } }

prueba en linea

Solución recursiva 2 ( respuesta original )

public class RomanToDecimalConverter { private static int convertRec(String s) { if (s.isEmpty()) return 0; if (s.startsWith("M")) return 1000 + convertRec(s.substring(1)); else if (s.startsWith("CM")) return 900 + convertRec(s.substring(2)); else if (s.startsWith("D")) return 500 + convertRec(s.substring(1)); else if (s.startsWith("CD")) return 400 + convertRec(s.substring(2)); else if (s.startsWith("C")) return 100 + convertRec(s.substring(1)); else if (s.startsWith("XC")) return 90 + convertRec(s.substring(2)); else if (s.startsWith("L")) return 50 + convertRec(s.substring(1)); else if (s.startsWith("XL")) return 40 + convertRec(s.substring(2)); else if (s.startsWith("X")) return 10 + convertRec(s.substring(1)); else if (s.startsWith("IX")) return 9 + convertRec(s.substring(2)); else if (s.startsWith("V")) return 5 + convertRec(s.substring(1)); else if (s.startsWith("IV")) return 4 + convertRec(s.substring(2)); else if (s.startsWith("I")) return 1 + convertRec(s.substring(1)); throw new IllegalArgumentException("Unexpected roman numerals"); } public static int convert(String s) { if (s == null || s.isEmpty() || !s.matches("^(M{0,3})(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$")) return -1; return convertRec(s); } }

prueba en linea


¿Qué hay de esta conversión? sin interruptor, sin estuche ...

PD: utilizo este script desde un shell bash

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


¿Qué tal esto?

int getdec(const string& input) { int sum=0; char prev=''%''; for(int i=(input.length()-1); i>=0; i--) { if(value(input[i])<sum && (input[i]!=prev)) { sum -= value(input[i]); prev = input[i]; } else { sum += value(input[i]); prev = input[i]; } } return sum; }


Acabo de hacerlo funcionar en Java, buen trabajo chicos.

public int getDecimal (String roman) { int decimal = 0; int romanNumber = 0; int prev = 0; for (int i = roman.length()-1; i >= 0; i--){ romanNumber = hashRomans.get(roman.charAt(i)); if(romanNumber < decimal && romanNumber != prev ){ decimal -= romanNumber; prev = romanNumber; } else { decimal += romanNumber; prev = romanNumber; } } return decimal; }


Como la mayoría de las respuestas aquí están en Java, estoy publicando la respuesta en C ++ (ya que estoy aburrido en este momento y no tengo nada más productivo que hacer :) Pero, por favor, no hay votaciones, excepto si el código es incorrecto. Known-issues = no manejará el desbordamiento

Código:

#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; }

// código de prueba

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; }


Encuentro que el siguiente enfoque es muy intuitivo:

public void makeArray(String romanNumeral){ int[] numberArray = new int[romanNumeral.length()]; for(int i=0; i<romanNumeral.length();i++){ char symbol = romanNumeral.charAt(i); switch(symbol){ case ''I'': numberArray[i] = 1; break; case ''V'': numberArray[i] = 5; break; case ''X'': numberArray[i] = 10; break; case ''L'': numberArray[i] = 50; break; case ''C'': numberArray[i] = 100; break; case ''D'': numberArray[i] = 500; break; case ''M'': numberArray[i] = 1000; break; } } calculate(numberArray); } public static void calculate(int[] numberArray){ int theNumber = 0; for(int n=0;n<numberArray.length;n++){ if(n !=numberArray.length-1 && numberArray[n] < numberArray[n+1]){ numberArray[n+1] = numberArray[n+1] - numberArray[n]; numberArray[n] = 0; } } for(int num:numberArray){ theNumber += num; } System.out.println("Converted number: " + theNumber); }


Esta es una variación modesta del algoritmo recursivo sugerido por 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"); }

Utiliza menos de 10 líneas de código efectivas.


Esta solución scala podría ser útil:

class RomanNumberConverter { private val toArabic = Map(''I'' -> 1, ''V'' -> 5, ''X'' -> 10, ''L'' -> 50, ''C'' -> 100, ''D'' -> 500, ''M'' -> 1000) // assume that correct roman number is provided def convert(romanNumber: String): Int = { def convert(rn: StringBuilder, lastDecimal: Int, acc: Int): Int = { if (rn.isEmpty) acc else { val thisDecimal = toArabic(rn.head) if (thisDecimal > lastDecimal) convert(rn.tail, thisDecimal, acc + thisDecimal - lastDecimal - lastDecimal) else convert(rn.tail, thisDecimal, acc + thisDecimal) } } val sb = new StringBuilder(romanNumber) convert(sb.tail, toArabic(sb.head), toArabic(sb.head)) } }


Esto debería funcionar:

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] ); } }


Menos código, más eficiente. No tan claro, lo siento!

public int evaluateRomanNumerals(String roman) { return (int) evaluateNextRomanNumeral(roman, roman.length() - 1, 0); } private double evaluateNextRomanNumeral(String roman, int pos, double rightNumeral) { if (pos < 0) return 0; char ch = roman.charAt(pos); double value = Math.floor(Math.pow(10, "IXCM".indexOf(ch))) + 5 * Math.floor(Math.pow(10, "VLD".indexOf(ch))); return value * Math.signum(value + 0.5 - rightNumeral) + evaluateNextRomanNumeral(roman, pos - 1, value); }


Pruebe esto: es simple y compacto y funciona sin problemas:

public static int ToArabic(string number) { if (number == string.Empty) return 0; if (number.StartsWith("M")) return 1000 + ToArabic(number.Remove(0, 1)); if (number.StartsWith("CM")) return 900 + ToArabic(number.Remove(0, 2)); if (number.StartsWith("D")) return 500 + ToArabic(number.Remove(0, 1)); if (number.StartsWith("CD")) return 400 + ToArabic(number.Remove(0, 2)); if (number.StartsWith("C")) return 100 + ToArabic(number.Remove(0, 1)); if (number.StartsWith("XC")) return 90 + ToArabic(number.Remove(0, 2)); if (number.StartsWith("L")) return 50 + ToArabic(number.Remove(0, 1)); if (number.StartsWith("XL")) return 40 + ToArabic(number.Remove(0, 2)); if (number.StartsWith("X")) return 10 + ToArabic(number.Remove(0, 1)); if (number.StartsWith("IX")) return 9 + ToArabic(number.Remove(0, 2)); if (number.StartsWith("V")) return 5 + ToArabic(number.Remove(0, 1)); if (number.StartsWith("IV")) return 4 + ToArabic(number.Remove(0, 2)); if (number.StartsWith("I")) return 1 + ToArabic(number.Remove(0, 1)); throw new ArgumentOutOfRangeException("something bad happened"); }


Será bueno si atraviesas en reversa.

public class RomanToDecimal { public static void romanToDecimal(java.lang.String romanNumber) { int decimal = 0; int lastNumber = 0; String romanNumeral = romanNumber.toUpperCase(); /* operation to be performed on upper cases even if user enters roman values in lower case chars */ for (int x = romanNumeral.length() - 1; x >= 0 ; x--) { char convertToDecimal = romanNumeral.charAt(x); switch (convertToDecimal) { case ''M'': decimal = processDecimal(1000, lastNumber, decimal); lastNumber = 1000; break; case ''D'': decimal = processDecimal(500, lastNumber, decimal); lastNumber = 500; break; case ''C'': decimal = processDecimal(100, lastNumber, decimal); lastNumber = 100; break; case ''L'': decimal = processDecimal(50, lastNumber, decimal); lastNumber = 50; break; case ''X'': decimal = processDecimal(10, lastNumber, decimal); lastNumber = 10; break; case ''V'': decimal = processDecimal(5, lastNumber, decimal); lastNumber = 5; break; case ''I'': decimal = processDecimal(1, lastNumber, decimal); lastNumber = 1; break; } } System.out.println(decimal); } public static int processDecimal(int decimal, int lastNumber, int lastDecimal) { if (lastNumber > decimal) { return lastDecimal - decimal; } else { return lastDecimal + decimal; } } public static void main(java.lang.String args[]) { romanToDecimal("XIV"); } }


Siguiendo su lógica de reducir 2 en IX, debe reducir 20 en XC 200 en CM y así sucesivamente.


Solución usando recursividad de cola:

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; } }

Pruebas:

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)); } }


Suponiendo números romanos bien formados:

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; } }


Usted puede verificar el siguiente código. Este código debería funcionar en todos los casos. También verifica la entrada nula o vacía y la entrada defectuosa (digamos que lo intentó con ABXI)

import java.util.HashMap; import org.apache.commons.lang3.StringUtils; public class RomanToDecimal { private HashMap<Character, Integer> map; public RomanToDecimal() { map = new HashMap<>(); map.put(''I'', 1); map.put(''V'', 5); map.put(''X'', 10); map.put(''L'', 50); map.put(''C'', 100); map.put(''D'', 500); map.put(''M'', 1000); } private int getRomanNumeralValue(char ch) { if (map.containsKey(ch)) { return map.get(ch); } else { throw new RuntimeException("Roman numeral string contains invalid characters " + ch); } } public int convertRomanToDecimal(final String pRomanNumeral) { if (StringUtils.isBlank(pRomanNumeral)) { throw new RuntimeException("Roman numeral string is either null or empty"); } else { int index = pRomanNumeral.length() - 1; int result = getRomanNumeralValue(pRomanNumeral.charAt(index)); for (int i = index - 1; i >= 0; i--) { if (getRomanNumeralValue(pRomanNumeral.charAt(i)) >= getRomanNumeralValue(pRomanNumeral.charAt(i + 1))) { result = result + getRomanNumeralValue(pRomanNumeral.charAt(i)); } else { result = result - getRomanNumeralValue(pRomanNumeral.charAt(i)); } } return result; } } public static void main(String... args){ System.out.println(new RomanToDecimal().convertRomanToDecimal("XCIX")); } }


Veamos este problema con 3 escenarios diferentes

Escenario 1:

Cuando vemos un patrón como el siguiente

''IIIIII'' or ''XXXXX'' or ''CCCC''

donde todos los caracteres son iguales: agregamos el valor de cada carácter en el patrón

''IIIIII'' gives us ''6'' ''XXXXX'' gives us ''50'' ''CCCC'' gives us ''400''

Escenario 2:

Cuando vemos 2 caracteres consecutivos diferentes donde el primero es menor en valor, entonces el segundo

''IX'' or ''XC''

Restamos el valor de primero de segundo ejemplo

second:''X'' gives us ''10'' first: ''I'' gives us ''1'' second - first : 10 - 1 = 9

Escenario 3:

Cuando vemos un 2 caracteres consecutivos diferentes donde el primero es mayor en valor, entonces el segundo

''XI'' or ''CX''

Añadimos primero y segundo ejemplo

second:''I'' gives us ''10'' first: ''X'' gives us ''1'' first + second : 10 + 1 = 11

Ahora podemos encontrar el resultado si hacemos esto recursivamente. Aquí está la implementación de Java:

//An array to be used for faster comparisons and reading the values private int[] letters26 = new int[26]; private void init () { letters26[''I'' - ''A''] = 1; letters26[''V'' - ''A''] = 5; letters26[''X'' - ''A''] = 10; letters26[''L'' - ''A''] = 50; letters26[''C'' - ''A''] = 100; letters26[''D'' - ''A''] = 500; letters26[''M'' - ''A''] = 1000; } public int convertRomanToInteger(String s) { //Initialize the array init(); return _convertRomanToInteger(s.toCharArray(), 0); } //Recursively calls itself as long as 2 consecutive chars are different private int _convertRomanToInteger(char[] s, int index) { int ret = 0; char pre = s[index];//Char from the given index ret = _getValue(pre); //Iterate through the rest of the string for (int i = index + 1; i < s.length; i++) { if (compare(s[i], s[i - 1]) == 0) { //Scenario 1: //If 2 consecutive chars are similar, just add them ret += _getValue(s[i]); } else if (compare(s[i], s[i - 1]) > 0) { //Scenario 2: //If current char is greater than the previous e.g IX (''I'' s[i - 1] and ''X'' s[i - 1]) //We need to calculate starting from ''i'' and subtract the calculation (''ret'') //done so far in current call return _convertRomanToInteger(s, i) - ret; } else { //Scenario 3: //If current char is smaller than the previous e.g XI (''X'' s[i - 1] and ''I'' s[i - 1]) //We need to calculate starting from ''i'' and subtract the result //from the calculation done so far in current call return ret + _convertRomanToInteger(s, i); } } return ret; } //Helper function for comparison private int compare(char a, char b) { return letters26[Character.toUpperCase(a) - ''A''] - letters26[Character.toUpperCase(b) - ''A'']; } private int _getValue(char c) { return letters26[Character.toUpperCase(c) - ''A'']; }


Versión completa con comprobación de errores y prueba todos los valores válidos en ambas direcciones (y algunos casos no válidos).

RomanNumeral.java

import java.util.ArrayList; import java.util.TreeMap; /** * Convert to and from a roman numeral string */ public class RomanNumeral { // used for converting from arabic number final static TreeMap<Integer, String> mapArabic = new TreeMap<Integer, String>(); // used for converting from roman numeral final static ArrayList<RomanDigit> mapRoman = new ArrayList<RomanDigit>(); final static int MAX_ARABIC = 3999; static { mapArabic.put(1000, "M"); mapArabic.put(900, "CM"); mapArabic.put(500, "D"); mapArabic.put(400, "CD"); mapArabic.put(100, "C"); mapArabic.put(90, "XC"); mapArabic.put(50, "L"); mapArabic.put(40, "XL"); mapArabic.put(10, "X"); mapArabic.put(9, "IX"); mapArabic.put(5, "V"); mapArabic.put(4, "IV"); mapArabic.put(1, "I"); mapRoman.add(new RomanDigit("M", 1000, 3, 1000)); mapRoman.add(new RomanDigit("CM", 900, 1, 90)); mapRoman.add(new RomanDigit("D", 500, 1, 100)); mapRoman.add(new RomanDigit("CD", 400, 1, 90)); mapRoman.add(new RomanDigit("C", 100, 3, 100)); mapRoman.add(new RomanDigit("XC", 90, 1, 9)); mapRoman.add(new RomanDigit("L", 50, 1, 10)); mapRoman.add(new RomanDigit("XL", 40, 1, 9)); mapRoman.add(new RomanDigit("X", 10, 3, 10)); mapRoman.add(new RomanDigit("IX", 9, 1, 0)); mapRoman.add(new RomanDigit("V", 5, 1, 1)); mapRoman.add(new RomanDigit("IV", 4, 1, 0)); mapRoman.add(new RomanDigit("I", 1, 3, 1)); } static final class RomanDigit { public final String numeral; public final int value; public final int maxConsecutive; public final int maxNextValue; public RomanDigit(String numeral, int value, int maxConsecutive, int maxNextValue) { this.numeral = numeral; this.value = value; this.maxConsecutive = maxConsecutive; this.maxNextValue = maxNextValue; } } /** * Convert an arabic integer value into a roman numeral string * * @param n The arabic integer value * @return The roman numeral string */ public final static String toRoman(int n) { if (n < 1 || n > MAX_ARABIC) { throw new NumberFormatException(String.format("Invalid arabic value: %d, must be > 0 and < %d", n, MAX_ARABIC)); } int leDigit = mapArabic.floorKey(n); //System.out.println("/t*** floor of " + n + " is " + leDigit); if (n == leDigit) { return mapArabic.get(leDigit); } return mapArabic.get(leDigit) + toRoman(n - leDigit); } /** * Convert a roman numeral string into an arabic integer value * @param s The roman numeral string * @return The arabic integer value */ public final static int toInt(String s) throws NumberFormatException { if (s == null || s.length() == 0) { throw new NumberFormatException("Invalid roman numeral: a non-empty and non-null value must be given"); } int i = 0; int iconsecutive = 0; // number of consecutive same digits int pos = 0; int sum = 0; RomanDigit prevDigit = null; while (pos < s.length()) { RomanDigit d = mapRoman.get(i); if (!s.startsWith(mapRoman.get(i).numeral, pos)) { i++; // this is the only place we advance which digit we are checking, // so if it exhausts the digits, then there is clearly a digit sequencing error or invalid digit if (i == mapRoman.size()) { throw new NumberFormatException( String.format("Invalid roman numeral at pos %d: invalid sequence ''%s'' following digit ''%s''", pos, s.substring(pos), prevDigit != null ? prevDigit.numeral : "")); } iconsecutive = 0; continue; } // we now have the match for the next roman numeral digit to check iconsecutive++; if (iconsecutive > d.maxConsecutive) { throw new NumberFormatException( String.format("Invalid roman numeral at pos %d: more than %d consecutive occurences of digit ''%s''", pos, d.maxConsecutive, d.numeral)); } // invalid to encounter a higher digit sequence than the previous digit expects to have follow it // (any digit is valid to start a roman numeral - i.e. when prevDigit == null) if (prevDigit != null && prevDigit.maxNextValue < d.value) { throw new NumberFormatException( String.format("Invalid roman numeral at pos %d: ''%s'' cannot follow ''%s''", pos, d.numeral, prevDigit.numeral)); } // good to sum sum += d.value; if (sum > MAX_ARABIC) { throw new NumberFormatException( String.format("Invalid roman numeral at pos %d: adding ''%s'' exceeds the max value of %d", pos, d.numeral, MAX_ARABIC)); } pos += d.numeral.length(); prevDigit = d; } return sum; } }

Main.java

public class Main { public static void main(String[] args) { System.out.println("TEST arabic integer => roman numeral string"); for (int i = 0; i<= 4000; i++) { String s; try { s = RomanNumeral.toRoman(i); } catch(NumberFormatException ex) { s = ex.getMessage(); } System.out.println(i + "/t =/t " + s); } System.out.println("TEST roman numeral string => arabic integer"); for (int i = 0; i<= 4000; i++) { String s; String msg; try { s = RomanNumeral.toRoman(i); int n = testToInt(s); assert(i == n); // ensure it is reflexively converting } catch (NumberFormatException ex) { System.out.println(ex.getMessage() + "/t =/t toInt() skipped"); } } testToInt("MMMM"); testToInt("XCX"); testToInt("CDC"); testToInt("IVI"); testToInt("XXC"); testToInt("CCD"); testToInt("MDD"); testToInt("DD"); testToInt("CLL"); testToInt("LL"); testToInt("IIX"); testToInt("IVX"); testToInt("IIXX"); testToInt("XCIX"); testToInt("XIWE"); // Check validity via a regexp for laughs String s = "IX"; System.out.println(s + " validity is " + s.matches("M{0,3}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})")); } private final static int testToInt(String s) { String msg; int n=0; try { n = RomanNumeral.toInt(s); msg = Integer.toString(n); } catch(NullPointerException | NumberFormatException ex) { msg = ex.getMessage(); } System.out.println(s + "/t =/t " + msg); return n; } }

Salida

TEST arabic integer => roman numeral string 0 = Invalid arabic value: 0, must be > 0 and < 3999 1 = I 2 = II 3 = III 4 = IV 5 = V 6 = VI 7 = VII 8 = VIII 9 = IX 10 = X ... [snip] ... 3988 = MMMCMLXXXVIII 3989 = MMMCMLXXXIX 3990 = MMMCMXC 3991 = MMMCMXCI 3992 = MMMCMXCII 3993 = MMMCMXCIII 3994 = MMMCMXCIV 3995 = MMMCMXCV 3996 = MMMCMXCVI 3997 = MMMCMXCVII 3998 = MMMCMXCVIII 3999 = MMMCMXCIX 4000 = Invalid arabic value: 4000, must be > 0 and < 3999 TEST roman numeral string => arabic integer Invalid arabic value: 0, must be > 0 and < 3999 = toInt() skipped I = 1 II = 2 III = 3 IV = 4 V = 5 VI = 6 VII = 7 VIII = 8 IX = 9 X = 10 ... [snip] ... MMMCMLXXXVIII = 3988 MMMCMLXXXIX = 3989 MMMCMXC = 3990 MMMCMXCI = 3991 MMMCMXCII = 3992 MMMCMXCIII = 3993 MMMCMXCIV = 3994 MMMCMXCV = 3995 MMMCMXCVI = 3996 MMMCMXCVII = 3997 MMMCMXCVIII = 3998 MMMCMXCIX = 3999 Invalid arabic value: 4000, must be > 0 and < 3999 = toInt() skipped MMMM = Invalid roman numeral at pos 3: more than 3 consecutive occurences of digit ''M'' XCX = Invalid roman numeral at pos 2: ''X'' cannot follow ''XC'' CDC = Invalid roman numeral at pos 2: ''C'' cannot follow ''CD'' IVI = Invalid roman numeral at pos 2: ''I'' cannot follow ''IV'' XXC = Invalid roman numeral at pos 2: invalid sequence ''C'' following digit ''X'' CCD = Invalid roman numeral at pos 2: invalid sequence ''D'' following digit ''C'' MDD = Invalid roman numeral at pos 2: more than 1 consecutive occurences of digit ''D'' DD = Invalid roman numeral at pos 1: more than 1 consecutive occurences of digit ''D'' CLL = Invalid roman numeral at pos 2: more than 1 consecutive occurences of digit ''L'' LL = Invalid roman numeral at pos 1: more than 1 consecutive occurences of digit ''L'' IIX = Invalid roman numeral at pos 2: invalid sequence ''X'' following digit ''I'' IVX = Invalid roman numeral at pos 2: invalid sequence ''X'' following digit ''IV'' IIXX = Invalid roman numeral at pos 2: invalid sequence ''XX'' following digit ''I'' XCIX = 99 XIWE = Invalid roman numeral at pos 2: invalid sequence ''WE'' following digit ''I'' IX validity is true


asumiendo que el hash se parece a esto

Hashtable<Character, Integer> ht = new Hashtable<Character, Integer>(); ht.put(''i'',1); ht.put(''x'',10); ht.put(''c'',100); ht.put(''m'',1000); ht.put(''v'',5); ht.put(''l'',50); ht.put(''d'',500);

entonces la lógica se vuelve bastante simple yendo por el dígito de derecha a izquierda

public static int rtoi(String num) { int intNum=0; int prev = 0; for(int i = num.length()-1; i>=0 ; i--) { int temp = ht.get(num.charAt(i)); if(temp < prev) intNum-=temp; else intNum+=temp; prev = temp; } return intNum; }


esta es una implementación muy básica de lo que pidió y que funciona para todos los casos de prueba. Si encuentra algo incorrecto que lo mencione, intentaré corregirlo también el código está en C ++.

int RomanToInt(string s){ int len = s.length(); map<char,int>mp; int decimal = 0; mp[''I''] = 1;mp[''V''] = 5;mp[''X''] = 10; mp[''L''] = 50;mp[''C''] = 100;mp[''D''] = 500;mp[''M''] = 1000; for(int i = 0; i < len ;i++){ char cur = s[i],fast = s[i+1]; int cur_val = mp[cur],fast_val = mp[fast]; if(cur_val < fast_val){ decimal = decimal - cur_val; }else{ decimal += cur_val; } } return decimal; }


Aquí está mi ...

import java.util.Scanner; class Solution { public static void main(String args[]) { Scanner sc = new Scanner(System.in); String num; // System.out.println("enter the number you want to convert from roman to integer."); num = "D"; System.out.println("length of string is " + num.length()); System.out.println("the integer number is :" + romanToInt(num) ); } public static int romanToInt(String s) { char I,V, X, L,C, D, M; char c1,c3, c2 = s.charAt(0); // System.out.println("the c2 is : " + (int)c2); int num = 0, num1 = 0; int j =0, k = 0, temp = 0; if (c2 == ''I'') { k = (int)c2 - 72; System.out.println("k is I" + k); } else if(c2 == ''V'') { k = (int)c2 - 81; System.out.println("K is V" + k); // return 86 - 81; } else if (c2 == ''X'') { k = (int)c2 - 78; System.out.println("K is X" + k); } else if (c2 == ''L'') { k = (int)c2 - 26; System.out.println("K is L" + k); } else if (c2 == ''C'') { k = (int)c2 + 33; System.out.println("K is C" + k); } else if (c2 == ''D'') { k = (int)c2 + 432; System.out.println("K is D" + k); } else if ( c2 == ''M'') { k = (int)c2 + 923; System.out.println("K is M" + k); } if (s.length() == 1){ num = k; } else { for(int i = 1; i<= s.length()-1 ; i++) { System.out.println("i is : " + i); c1 = s.charAt(i); if (i == s.length() - 1) { temp = 0; } else { c3 = s.charAt(i+1); if (c3 == ''I'') { temp = (int)c3 - 72; System.out.println("temp is I " + temp); } else if(c3 == ''V'') { temp = (int)c3 - 81; System.out.println("temp is I " + temp); // return 86 - 81; } else if (c3 == ''X'') { temp = (int)c3 - 78; System.out.println("temp is I " + temp); } else if (c3 == ''L'') { temp = (int)c3 - 26; System.out.println("temp is I " + temp); } else if (c3 == ''C'') { temp = (int)c3 + 33; System.out.println("temp is I " + temp); } else if (c3 == ''D'') { temp = (int)c3 + 432; System.out.println("temp is I " + temp); } else if ( c3 == ''M'') { temp = (int)c3 + 923; System.out.println("temp is I " + temp); } } if (c1 == ''I'') { j = (int)c1 - 72; System.out.println("j is I " + j); } else if(c1 == ''V'') { j = (int)c1 - 81; System.out.println("j is V " + j); // return 86 - 81; } else if (c1 == ''X'') { j = (int)c1 - 78; System.out.println("j is X " + j); } else if (c1 == ''L'') { j = (int)c1 - 26; System.out.println("j is L " + j); } else if (c1 == ''C'') { j = (int)c1 + 33; System.out.println("j is C " + j); } else if (c1 == ''D'') { j = (int)c1 + 432; System.out.println("j is D " + j); } else if ( c1 == ''M'') { j = (int)c1 + 923; System.out.println("j is M " + j); } if ( k < j && j>temp ) { k = j - k ; num = num + k; } else if (j==k || j<k || j<temp){ num = num + k ; // k = j; } if (j>k ) { k = temp; i += 1; if (i == s.length()-1) { num = num + k; } } else { k = j; if (i == s.length()-1) { num = num + k; } } } } return num; } }


public class RomInt { String roman; int val; void assign(String k) { roman=k; } private class Literal { public char literal; public int value; public Literal(char literal, int value) { this.literal = literal; this.value = value; } } private final Literal[] ROMAN_LITERALS = new Literal[] { new Literal(''I'', 1), new Literal(''V'', 5), new Literal(''X'', 10), new Literal(''L'', 50), new Literal(''C'', 100), new Literal(''D'', 500), new Literal(''M'', 1000) }; public int getVal(String s) { int holdValue=0; for (int j = 0; j < ROMAN_LITERALS.length; j++) { if (s.charAt(0)==ROMAN_LITERALS[j].literal) { holdValue=ROMAN_LITERALS[j].value; break; } //if() }//for() return holdValue; } //getVal() public int count() { int count=0; int countA=0; int countB=0; int lastPosition = 0; for(int i = 0 ; i < roman.length(); i++) { String s1 = roman.substring(i,i+1); int a=getVal(s1); countA+=a; } for(int j=1;j<roman.length();j++) { String s2= roman.substring(j,j+1); String s3= roman.substring(j-1,j); int b=getVal(s2); int c=getVal(s3); if(b>c) { countB+=c; } } count=countA-(2*countB); return count; } void disp() { int result=count(); System.out.println("Integer equivalent of "+roman+" = " +result); } } //RomInt---BLC


// Author: Francisco Edmundo private int translateNumber(String texto) { int n = 0; int numeralDaDireita = 0; for (int i = texto.length() - 1; i >= 0; i--) { int valor = (int) translateNumber(texto.charAt(i)); n += valor * Math.signum(valor + 0.5 - numeralDaDireita); numeralDaDireita = valor; } return n; } private double translateNumber(char caractere) { return Math.floor(Math.pow(10, "IXCM".indexOf(caractere))) + 5 * Math.floor(Math.pow(10, "VLD".indexOf(caractere))); }


//Bet no one has a smaller and easier logic than this........Open CHALLENGE!!!!!!! import java.io.*; class Convertion_practical_q2 { void Decimal()throws IOException //Smaller code for convertion from roman to decimal { DataInputStream in=new DataInputStream(System.in); System.out.println("Enter the number"); String num=in.readLine(); char pos[]={''0'',''I'',''V'',''X'',''L'',''C'',''D'',''M''}; int l1=7; //l1 is size of pos array String v[]={"","1","5","10","50","100","500","1000"}; int l=num.length(); int p=0,p1=0,sum=0; for(int i=l-1;i>=0;i--) { char ch=num.charAt(i); for(int j=1;j<=l1;j++) { if(ch==pos[j]) p=j; } if(p>=p1) sum+=Integer.parseInt(v[p]); else sum-=Integer.parseInt(v[p]); //System.out.println("sum ="+sum+"/np="+p+"/np1="+p1); p1=p; } System.out.println(sum); } }


public class RomanNumeral { private final Map<Integer, String> arabicToRoman = new LinkedHashMap<Integer, String>(); private final Map<String, Integer> romanToArabic = new LinkedHashMap<String, Integer>(); public RomanNumeral() { arabicToRoman.put(10, "X"); arabicToRoman.put(9, "IX"); arabicToRoman.put(5, "V"); arabicToRoman.put(4, "IV"); arabicToRoman.put(1, "I"); romanToArabic.put("X", 10); romanToArabic.put("V", 5); romanToArabic.put("I", 1); } public String convertToRomanNumeral(int number) { String result = ""; for (Integer i : arabicToRoman.keySet()) { while (number >= i) { result += arabicToRoman.get(i); number -= i; } } return result; } public String convertToArabicNumber(String romanNumeral) { int result = 0; int top = 0; for (int i = romanNumeral.length() - 1; i >= 0; i--) { char current = romanNumeral.charAt(i); int value = romanToArabic.get("" + current); if (value < top) { result -= value; } else { result += value; top = value; } } return "" + result; } }


public static int convertFromRoman(String romanNumeral) { Character[] rnChars = { ''M'', ''D'', ''C'', ''L'', ''X'', ''V'', ''I'' }; int[] rnVals = { 1000, 500, 100, 50, 10, 5, 1 }; HashMap<Character, Integer> valueLookup = new HashMap<Character, Integer>(); for (int i = 0; i < rnChars.length;i++) valueLookup.put(rnChars[i], rnVals[i]); int retVal = 0; for (int i = 0; i < romanNumeral.length();i++) { int addVal = valueLookup.get(romanNumeral.charAt(i)); retVal += i < romanNumeral.length()-1 && addVal < valueLookup.get(romanNumeral.charAt(i+1))? -addVal:addVal; } return retVal; }