Convert numbers to Roman Numerials in Swift
Roman numerals, from ancient Rome are a way of writing numbers using these letters from the latin alphabet [I, V, X, L, C, D and M]. Each letter has a fixed integer value and can be combined to represent any number from 1 to 3999. This article demonstrates how to convert a integer to the Roman Numeral representation.
Roman numerals are composed of combinations of the following seven letters that are combined to represent any number from 1 to 3999.
Roman numeral building blocks
Letter | Value | Name |
---|---|---|
I | 1 | unus |
V | 5 | quinque |
X | 10 | decem |
L | 50 | quinquaginta |
C | 100 | centum |
D | 500 | quingenti |
M | 1000 | mille |
Repeating characters
Roman numerals are composed of repeating the base 10 characters up to 3 times. Such as 1, 2, 3 are repeats of the unus symbol 1, 2 and 3 times respectively. The repeating parameter is used to create a string with the appropriate number of the character.
1String(repeating: "I", count:1)
2// I
3
4String(repeating: "I", count:2)
5// II
6
7String(repeating: "I", count:3)
8// III
Treat 4 and 9 as their own character set
The key to programatically converting a number to Roman Numerals is to treat the 4, 9 and equivalent characters as their own digit. Then start with integer division from the highest to the lowest number, when the division result is greater than zero, that result is the number of the equivalent character in Roman numerals. The remainder from the division is fed into the next round of division by the next highest number.
Programatic building blocks for Roman numerals
Letter | Value |
---|---|
I | 1 |
IV | 4 |
V | 5 |
IX | 9 |
X | 10 |
XL | 40 |
L | 50 |
XC | 90 |
C | 100 |
CD | 400 |
D | 500 |
CM | 900 |
M | 1000 |
Take an example of the number 7
Programatic building blocks for Roman numerals
Letter | Value | 6 division | remainder |
---|---|---|---|
X | 10 | 0 | - |
IX | 9 | 0 | - |
V | 5 | 1 | 2 |
Roman Numeral is composed of 1 V. Remainder 2 is used with the next highest number (4).
Programatic building blocks for Roman numerals
Letter | Value | 2 division | remainder |
---|---|---|---|
IV | 4 | 0 | 2 |
I | 1 | 2 | 0 |
Roman Numeral is composed of 2 I
Result is VII
Swift Code
Create a Converter struct with a static function to convert numeric values to Roman Numerals. A guard statement is used to ensure the value is between 1 and 3999. It is important that these are ordered from highest to lowest so the highest numbers are converted first and then removed. This process is repeated with the remainder and the next highest number and so on down to the number 1 and the letter "I". The zip function is used to create a sequence of tuples from a list of Arabic numbers and a list of Roman numeral symbols.
1struct Converter {
2
3 static func romanNumeralFor(_ n:Int) -> String {
4 guard n > 0 && n < 4000 else {
5 return "Number must be between 1 and 3999"
6 }
7
8 var returnString = ""
9 let arabicNumbers = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1]
10 let romanLetters = [ "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"]
11
12 var num = n
13 for (ar, rome) in zip(arabicNumbers, romanLetters) {
14 let repeats = num / ar
15 returnString += String(repeating: rome, count: repeats)
16 num = num % ar
17 }
18 return returnString
19 }
20}
App ViewModel
Create a ConverterViewModel
to call the Converter and set variables for the Roman
and Arabic numbers as well as an error message.
1class ConverterViewModel: ObservableObject {
2 @Published var roman: String
3 @Published var arabic: String
4 @Published var error: String
5
6 init() {
7 roman = "I"
8 arabic = "1"
9 error = ""
10 }
11
12 func convertNumber() {
13 error = ""
14 if let n = Int(arabic) {
15 guard n > 0 && n < 4000 else {
16 roman = ""
17 error = "Number must be between 1 and 3999"
18 return
19 }
20 roman = Converter.romanNumeralFor(n)
21 } else {
22 roman = ""
23 error = "'\(arabic)' is not a valid number"
24 }
25 }
26}
SwiftUI View
Create a SwiftUI view consisting of a form and an action button to call the conversion. A TextField is used to allow the user to enter a number to convert and the Roman Numerals are displayed in a Text view.
1struct RomanNumeralsView: View {
2 @StateObject private var vm = ConverterViewModel()
3
4 var body: some View {
5 VStack {
6 Text("Roman Numerals")
7 .font(.title)
8 .padding()
9
10 Form {
11 Section(header: Text("Numver to convert"),
12 footer: Text("\(vm.error)").foregroundColor(.red)) {
13 TextField("Number", text: $vm.arabic)
14 }
15
16 Section(header: Text("Roman Numerals")) {
17 Text("\(vm.roman)")
18 .font(.title)
19 }
20 }
21 .frame(width: 350, height: 250, alignment: .center)
22 .padding()
23
24 Button("Convert") {
25 vm.convertNumber()
26 }
27 .buttonStyle(ActionButtonStyle())
28
29 Spacer()
30 }
31 }
32}
Roman Numerals for year 2021 in SwiftUI app
Basic error handling is added to inform the user when invalid data has been entered, such as non-numeric data or numbers outside of the range 1 to 3999.
Error handling for invalid number or number out of range
Conclusion
This article how to convert a number to Roman Numerals. The solution is to loop through a set of Roman Numeral symbols from the highest to lowest. For each symbol in the list; divide by the number and add this amount of the symbol to the result, continue the loop with the remainder. There are 7 symbols used [I, V, X, L, C, D and M], but it is easier to use additional symbol-pairs for the 4,9,40, etc. numbers [I, IV, V, IX, X, XL. L, XC, C, CD, D, CM and M], then each symbol can be treated the same.