Code example:

func romanToDecimal(romeChar: String) { var result = 0 var maxValue = 0 let romeCh = romeChar.uppercased().replacingOccurrences(of: "\n", with: "", options: NSString.CompareOptions.literal, range: nil) let romeNumerals = ["M": 1000, "D": 500, "C": 100, "L": 50, "X": 10, "V": 5, "I": 1] for vp in romeNumerals { let val = vp.value let key = vp.key if (romeCh.range(of: key) != nil) { maxValue = max(val, maxValue) result += val == maxValue ? val : -val } } print(result) } 

The problem is that there is an incorrect calculus of the final result.

  • I see the swift for the first time, but something tells me that as soon as M is found in the string (which, in theory, it is searched first, because it is at the beginning of the array) then maxValue will be 1000 and with all subsequent checks it will remain so (after all, it is more than the other numbers ). And romeCh.range(of: key) probably checks for the presence of a digit, but does not take into account the number of digits and VIII is likely to be counted as 5 + 1 - Mike
  • and in general, this check with maxValue is probably designed for processing the input line in order (what figure to understand before), but for some reason the cycle is on the array of numbers and not on the line ... - Mike
  • apparently the logic is not correct - tried MCM, got 1100 instead of 1900. - Max Mikheyenko
  • Yes, no, it takes as it is the value you need. For example, XC correctly holds 90, but if 3 or more characters are wrong - Orest Mykha
  • Carefully read my first 2 comments. In principle, it is not capable of more than 2 letters and then translate in the correct order. Try it, I should give 1 according to this algorithm, But III by the fact that I can see here, will also be equal to 1, because I don’t see where the number of digits would be considered here -

2 answers 2

Algorithm proposed by @Qwertiy swifted in free form

 func convert(roman:String) -> Int { let romeNumerals = ["M": 1000, "D": 500, "C": 100, "L": 50, "X": 10, "V": 5, "I": 1] var result = 0 for (index, i) in roman.characters.enumerated() { if(index < roman.characters.count-1 && romeNumerals[String(i)]! < romeNumerals[String(roman.characters[roman.index(roman.startIndex, offsetBy: index+1)])]!) { result -= romeNumerals[String(i)]! } else { result += romeNumerals[String(i)]! } } return result } 
  • Very grateful! - Orest Mykha

Here is the correct algorithm, how to rewrite it to swift, I do not know:

 function convert(roman) { var values = {I: 1, V: 5, X: 10, L: 50, C: 100, D: 500, M: 1000}; var digits = Object.keys(values); roman = roman.toUpperCase(); var res = 0; for (var q=0; q<roman.length; ++q) { if (digits.indexOf(roman[q]) < digits.indexOf(roman[q+1])) { res -= values[roman[q]]; } else { res += values[roman[q]]; } } return res; } document.querySelector('input').addEventListener('input', function (e) { document.querySelector('output').textContent = convert(e.target.value); }); 
 input:invalid + output { display: none } 
 <input type="text" pattern="[IVXLCDMivxlcdm]+"> <output></output> 

  • I wonder how correct it is to convert strings like "xxiiiiiiiiiiivi". EMNIP, there are two systems for recording numbers in Roman numerals, and the string I mentioned does not fit into one of them. In theory, in this case, it is necessary to throw an exception, or whatever is in% of the% question-language% taken ... ps I'm not finding fault)) I just wondered how to do it right if I did it myself - 4per
  • @ 4per, yeah, but no one asked for validation. If the number is written correctly (including, in a simplified form), then everything works. If it is incorrect .. Well, it also does not fall :) - Qwertiy
  • traditionally, it is believed that only one character can be to the left of the larger those. 8 can be written like this VIII but not like this IIX - Max Mikheyenko
  • @MaxMikheyenko, IL is considered a simplified form instead of XLIX , etc. - Qwertiy 10:10