Skip to content

Instantly share code, notes, and snippets.

@Codelaby
Last active October 16, 2023 15:52
Show Gist options
  • Save Codelaby/05e6bbacf47cbbb474cd59e8048554a7 to your computer and use it in GitHub Desktop.
Save Codelaby/05e6bbacf47cbbb474cd59e8048554a7 to your computer and use it in GitHub Desktop.
Roman number conversor
import Foundation
class RomanConverter {
enum Symbol: String, CaseIterable {
case I = "I", IV = "IV", V = "V", IX = "IX", X = "X", XL = "XL", L = "L", XC = "XC", C = "C", CD = "CD", D = "D", CM = "CM", M = "M"
var decimalValue: Int {
switch self {
case .I: return 1
case .IV: return 4
case .V: return 5
case .IX: return 9
case .X: return 10
case .XL: return 40
case .L: return 50
case .XC: return 90
case .C: return 100
case .CD: return 400
case .D: return 500
case .CM: return 900
case .M: return 1000
}
}
static func closestBelow(_ value: Int) -> Symbol? {
return Symbol.allCases.sorted(by: { $0.decimalValue > $1.decimalValue })
.first { value >= $0.decimalValue }
}
static func highestStartingSymbol(_ value: String) -> Symbol? {
return Symbol.allCases.sorted(by: { $0.decimalValue > $1.decimalValue })
.first { value.hasPrefix($0.rawValue) }
}
}
func toRomanNumeral(_ value: Int) -> String {
var result = ""
var remainingValue = value
while remainingValue > 0 {
if let closestSymbol = Symbol.closestBelow(remainingValue) {
result += closestSymbol.rawValue
remainingValue -= closestSymbol.decimalValue
}
}
return result
}
func toDecimal(_ romanNumeral: String) -> Int {
var result = 0
var remainingRomanNumeral = romanNumeral
while !remainingRomanNumeral.isEmpty {
if let highestSymbol = Symbol.highestStartingSymbol(remainingRomanNumeral) {
result += highestSymbol.decimalValue
remainingRomanNumeral.removeFirst(highestSymbol.rawValue.count)
}
}
return result
}
}
func testRomanArabicConversions() -> Bool {
var success = true
let converter = RomanConverter()
for number in 1...4999 {
let romanNumeral = converter.toRomanNumeral(number)
let arabicValue = converter.toDecimal(romanNumeral)
if arabicValue != number {
print("Error: Conversion mismatch for \(number). Expected: \(romanNumeral), Got: \(arabicValue)")
success = false
}
}
return success
}
let conversionTestResult = testRomanArabicConversions()
if conversionTestResult {
print("Todas las conversiones entre números arábigos y números romanos coinciden.")
} else {
print("Al menos una conversión entre números arábigos y números romanos no coincide.")
}
import Foundation
class RomanConverter {
func romanToInt(_ s: String) -> Int {
let romanValues: [Character: Int] = [
"I": 1, "V": 5, "X": 10, "L": 50, "C": 100, "D": 500, "M": 1000
]
var result = 0
var prevValue = 0
for char in s.reversed() {
if let value = romanValues[char] {
if value < prevValue {
result -= value
} else {
result += value
}
prevValue = value
}
}
return result
}
func intToRoman(_ n: Int) -> String {
guard n > 0 && n < 4000 else {
return "Number must be between 1 and 3999"
}
var returnString = ""
let arabicNumbers = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1]
let romanLetters = [ "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"]
var num = n
for (ar, rome) in zip(arabicNumbers, romanLetters) {
let repeats = num / ar
returnString += String(repeating: rome, count: repeats)
num %= ar
}
return returnString
}
func generateRomanNumbersWithPattern(pattern: String) -> [String] {
var romanNumbers: [String] = []
for number in 1...9999 {
let romanNumber = intToRoman(number)
// Reemplazar "?" con "[IVXLCDM]*" en el patrón
let regexPattern = pattern.replacingOccurrences(of: "?", with: "[IVXLCDM]*")
if let _ = romanNumber.range(of: "^" + regexPattern + "$", options: .regularExpression) {
romanNumbers.append(romanNumber)
}
}
let stringLength = pattern.count
let filteredStrings = romanNumbers.filter { $0.count == stringLength }
return filteredStrings
}
func testRomanDateConversion() {
let converter = RomanConverter()
let romanNumber = "MCMXCIV"
let integerValue = converter.romanToInt(romanNumber)
print("El número romano \(romanNumber) equivale a \(integerValue)")
let arabicValue = 1994
let romanEquivalent = converter.intToRoman(arabicValue)
print("El número \(arabicValue) equivale a \(romanEquivalent) en romanos")
// Test cases for Roman to Integer conversion
let romanDatesToIntegers: [(String, Int)] = [
("I", 1),
("IV", 4),
("IX", 9),
("XIV", 14),
("XX", 20),
("XLII", 42),
("LXIX", 69),
("XCIV", 94),
("C", 100),
("CD", 400),
("CDXCIX", 499),
("DCCC", 800),
("CM", 900),
("MCMXCIV", 1994),
]
for (romanDate, integerDate) in romanDatesToIntegers {
let result = converter.romanToInt(romanDate)
assert(result == integerDate, "Error: Roman to Integer conversion failed for \(romanDate). Expected: \(integerDate), Got: \(result)")
}
// Test cases for Integer to Roman conversion
let integerDatesToRomans: [(Int, String)] = [
(1, "I"),
(4, "IV"),
(9, "IX"),
(14, "XIV"),
(20, "XX"),
(42, "XLII"),
(69, "LXIX"),
(94, "XCIV"),
(100, "C"),
(400, "CD"),
(499, "CDXCIX"),
(800, "DCCC"),
(900, "CM"),
(1980, "MCMLXXX"),
(1994, "MCMXCIV"),
]
for (integerDate, romanDate) in integerDatesToRomans {
let result = converter.intToRoman(integerDate)
assert(result == romanDate, "Error: Integer to Roman conversion failed for \(integerDate). Expected: \(romanDate), Got: \(result)")
}
print("All Roman date conversion tests passed.")
}
}
//valid I to MMMMCMXCIX
func isRomanNumeral(string: String) -> Bool {
let regex = try! NSRegularExpression(pattern: "^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$", options: .caseInsensitive)
let range = NSRange(location: 0, length: string.utf16.count)
let matches = regex.matches(in: string, options: [], range: range)
return !matches.isEmpty
}
//valido entre 1 a 4999
func isValidArabicNotation(string: String) -> Bool {
let pattern = "^[1-4][0-9]{0,3}$"
let regex = try! NSRegularExpression(pattern: pattern, options: .caseInsensitive)
let range = NSRange(location: 0, length: string.utf16.count)
return regex.firstMatch(in: string, options: [], range: range) != nil
}
let arabicData = "5000"
let isValid = isValidArabicNotation(string: arabicData)
print(isValid) // true
let mdata = "MCMLXXIV"
let isValidRomanNumeral = isRomanNumeral(string: mdata)
print(isValidRomanNumeral) // true
@Codelaby
Copy link
Author

Codelaby commented Oct 16, 2023

Explain how 4999 is MMMMCMXCIX in Roman Numerals:
M (1000) + M (1000) + M (1000) + M (1000) + CM (900) + XC (90) + IX (9) = 4999

https://www.online-stopwatch.com/roman-numerals/4997/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment