-8

So I am building a sample project which takes roman numerals and converts it to a base10 digit. I tried getting this to work but have not accomplished my goal. Is there anyone who knows how to accomplish this? I am adding the roman numerals up to 10 below for reference. Thanks!

1 - I 2 - II 3 - III 4 - IV 5 - V 6 - VI 7 - VII 8 - VIII 9 - IX 10 - X

Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
SteveSmith
  • 269
  • 2
  • 12
  • 3
    Update your question with what you have tried so far. – rmaddy Apr 30 '16 at 00:37
  • @rmaddy honestly I deleted everyhting because I don't even think I was on the right track...sorry – SteveSmith Apr 30 '16 at 00:39
  • The [following search results](http://stackoverflow.com/search?q=convert+roman+numerals+) should help. Shouldn't be too hard to translate Java (or other) code to Swift. – rmaddy Apr 30 '16 at 00:42
  • @rmaddy I clicked the link and didn't find exactly what I was looking for. Could you point to the right one if you spotted it? Thanks I appreciate the help! – SteveSmith Apr 30 '16 at 00:44
  • Try this one: http://stackoverflow.com/a/9073310/1226963 – rmaddy Apr 30 '16 at 00:47
  • @rmaddy I believe it shows how to convert to decimal but I think I may be able to work with it. Thanks – SteveSmith Apr 30 '16 at 00:48
  • No, it clearly converts Roman to decimal. – rmaddy Apr 30 '16 at 00:50
  • @rmaddy Yup exactly. I need it to convert a Roman Numeral string into an integer not a decimal. – SteveSmith Apr 30 '16 at 00:53
  • By "decimal" I meant base 10. That answer does exactly what you want. – rmaddy Apr 30 '16 at 00:56
  • @rmaddy Just looked through it and it works fine. Do you know of any answers in Swift or are you aware of any convertors online? – SteveSmith Apr 30 '16 at 01:01
  • @DuncanC Hey dude thanks for the philosophy. I have been programming for only 5 months as of now. Swift was my first language... Can I at LEAST get a hang of one before I move to another? – SteveSmith Apr 30 '16 at 01:10

2 Answers2

6

All you need is to iterate through your roman string characters in a reverse way and map those characters values. Start with maxValue equal to zero, switch the letters value, save it as the maxValue and if the value is equal to maxValue add it otherwise subtract the actual value. You can also use regex (strict or not) to validate and throw an error in case it fails. Try like this:

Xcode 9.x • Swift 4.x

Note: for Swift 3 version or earlier check the edit history.

extension String {
    enum RomanParsingError: Error {
        case invalidNumber
    }
    func romanNumeralValue() throws -> Int  {
        guard range(of: "^(?=[MDCLXVI])M*(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$", options: .regularExpression) != nil else {
            throw RomanParsingError.invalidNumber
        }
        var result = 0
        var maxValue = 0
        uppercased().reversed().forEach {
            let value: Int
            switch $0 {
            case "M":
                value = 1000
            case "D":
                value = 500
            case "C":
                value = 100
            case "L":
                value = 50
            case "X":
                value = 10
            case "V":
                value = 5
            case "I":
                value = 1
            default:
                value = 0
            }
            maxValue = max(value, maxValue)
            result += value == maxValue ? value : -value
        }
        return result
    }
}

usage:

do {
    let decimal = try "MCMLXXVIII".romanNumeralValue()
    print(decimal)   // 1978
} catch {
    print(error)
}


do {
    let decimal = try "IIIV".romanNumeralValue()
    print(decimal)
} catch {
    print(error)   // "invalidNumber\n"
}
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
  • Actually I think your approach WILL work. – Duncan C Apr 30 '16 at 01:54
  • @LeoDabus Can you convert that into a function that takes in a String(which would be the Roman Numeral)? I am really new to this and appreciate the help! – SteveSmith Apr 30 '16 at 03:35
  • I will then go ahead and mark your answer right and up vote it right away!! – SteveSmith Apr 30 '16 at 03:41
  • 1
    @SteveSmith I think you can put this into a function by yourself. Just take everything from `var result = 0` to `return result` and put that in your function with a parameter and change `uppercaseString etc...` to `[parameter_name].uppercaseString etc...`. But why wouldn't you want to just use a clean extension? What difference does it make? – brimstone Apr 30 '16 at 03:52
  • @brimstone I tried on my own to do it and got it to kinda work. So before I asked I put my best effort. There is nothing wrong with the extension I just wanted to see it both ways that is all. – SteveSmith Apr 30 '16 at 04:20
  • @LeoDabus Lastly if there is a way to show an error message for invalid entries would be cool also!!!! – SteveSmith Apr 30 '16 at 04:28
  • This is a nice answer, but it also processes digit combinations that are illegal, such as IIIV → 2, but 2 would be II. – vikingosegundo Apr 30 '16 at 22:40
  • 1
    ok, problem solved :) – vikingosegundo Apr 30 '16 at 22:43
  • can u please explain what does this line means if range(of: "^(?=[MDCLXVI])M*(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$", options: .regularExpression) == nil { throw NSError(domain: "NotValidRomanNumber", code: -1, userInfo: nil) } – mAc May 30 '17 at 16:41
  • https://regex101.com – Leo Dabus May 30 '17 at 17:17
  • Regex is part of Foundation? What's the alternative if can not import Foundation? – habibiboss Sep 19 '21 at 20:50
  • @habibiboss you would need to validade the regex manually – Leo Dabus Mar 17 '22 at 13:27
1

Roman numerals do not have a one-to-one mapping to decimal digits. You mapped out the sequences of roman numerals from 1 to 9 (single decimal digits.) There are also roman numerals for 10, 50, 100, 500, and 1000.

If you want to convert a large number in roman numerals to decimal, you need to parse it. You'll need to handle those larger units first.

Map out on paper how you do the conversion yourself, in small steps. Then write those steps out in pseudocode. (Don't worry about syntax, just map out the steps.)

Finally, use your pseudocode as a guide to writing your Swift program.

Duncan C
  • 128,072
  • 22
  • 173
  • 272