Conversion entre chiffres romains et arabes en Java

Conversion entre chiffres romains et arabes en Java

1. introduction

Les anciens Romains développèrent leur propre système numérique appelé chiffres romains. Le système utilise des lettres avec différentes valeurs pour représenter des nombres. Les chiffres romains sont encore utilisés aujourd'hui dans certaines applications mineures.

Dans ce didacticiel, nous allons implémentersimple converters that will transform numbers from one system to the other.

2. Chiffres romains

Dans le système romain, nous avons7 symbols that represent numbers:

  • I représente 1

  • V représente 5

  • X représente 10

  • L représente 50

  • C représente 100

  • D représente 500

  • M représente 1000

À l’origine, les gens représentaient un 4 avec IIII ou 40 avec XXXX. Cela peut être assez inconfortable à lire. Il est également facile de confondre quatre symboles côte à côte avec trois symboles.

Roman numerals use subtractive notation pour éviter de telles erreurs. Au lieu de direfour times one (IIII), on peut dire que c'estone less than five (IV).

En quoi est-ce important de notre point de vue? C’est important car au lieu d’ajouter simplement des nombres symbole par symbole, nous pourrions avoir besoin de vérifier le symbole suivant pour déterminer si le nombre doit être ajouté ou soustrait.

3. Modèle

Définissons une énumération pour représenter les chiffres romains:

enum RomanNumeral {
    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);

    private int value;

    RomanNumeral(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }

    public static List getReverseSortedValues() {
        return Arrays.stream(values())
          .sorted(Comparator.comparing((RomanNumeral e) -> e.value).reversed())
          .collect(Collectors.toList());
    }
}

Notez que nous avons défini des symboles supplémentaires pour aider à la notation soustractive. Nous avons également défini une méthode supplémentaire nomméegetReverseSortedValues().

Cette méthode nous permettra d’extraire explicitement les chiffres romains définis dans l’ordre décroissant.

4. Du romain à l'arabe

Roman numerals can only represent integers between 1 to 4000. Nous pouvons utiliser l'algorithme suivant pour convertir un chiffre romain en nombre arabe (en parcourant les symboles dans l'ordre inverse deM àI):

LET numeral be the input String representing an Roman Numeral
LET symbol be initialy set to RomanNumeral.values()[0]
WHILE numeral.length > 0:
    IF numeral starts with symbol's name:
        add symbol's value to the result
        remove the symbol's name from the numeral's beginning
    ELSE:
        set symbol to the next symbol

4.1. la mise en oeuvre

Ensuite, nous pouvons implémenter l'algorithme en Java:

public static int romanToArabic(String input) {
    String romanNumeral = input.toUpperCase();
    int result = 0;

    List romanNumerals = RomanNumeral.getReverseSortedValues();

    int i = 0;

    while ((romanNumeral.length() > 0) && (i < romanNumerals.size())) {
        RomanNumeral symbol = romanNumerals.get(i);
        if (romanNumeral.startsWith(symbol.name())) {
            result += symbol.getValue();
            romanNumeral = romanNumeral.substring(symbol.name().length());
        } else {
            i++;
        }
    }

    if (romanNumeral.length() > 0) {
        throw new IllegalArgumentException(input + " cannot be converted to a Roman Numeral");
    }

    return result;
}

4.2. Test

Enfin, nous pouvons tester la mise en œuvre:

@Test
public void given2018Roman_WhenConvertingToArabic_ThenReturn2018() {
    String roman2018 = "MMXVIII";

    int result = RomanArabicConverter.romanToArabic(roman2018);

    assertThat(result).isEqualTo(2018);
}

5. De l'arabe au romain

Nous pouvons utiliser l'algorithme suivant pour convertir des chiffres arabes en chiffres romains (en parcourant les symboles dans l'ordre inverse deM àI):

LET number be an integer between 1 and 4000
LET symbol be RomanNumeral.values()[0]
LET result be an empty String
WHILE number > 0:
    IF symbol's value <= number:
        append the result with the symbol's name
        subtract symbol's value from number
    ELSE:
        pick the next symbol

5.1. la mise en oeuvre

Ensuite, nous pouvons maintenant implémenter l'algorithme:

public static String arabicToRoman(int number) {
    if ((number <= 0) || (number > 4000)) {
        throw new IllegalArgumentException(number + " is not in range (0,4000]");
    }

    List romanNumerals = RomanNumeral.getReverseSortedValues();

    int i = 0;
    StringBuilder sb = new StringBuilder();

    while ((number > 0) && (i < romanNumerals.size())) {
        RomanNumeral currentSymbol = romanNumerals.get(i);
        if (currentSymbol.getValue() <= number) {
            sb.append(currentSymbol.name());
            number -= currentSymbol.getValue();
        } else {
            i++;
        }
    }

    return sb.toString();
}

5.2. Test

Enfin, nous pouvons tester la mise en œuvre:

@Test
public void given1999Arabic_WhenConvertingToRoman_ThenReturnMCMXCIX() {
    int arabic1999 = 1999;

    String result = RomanArabicConverter.arabicToRoman(arabic1999);

    assertThat(result).isEqualTo("MCMXCIX");
}

6. Conclusion

Dans cet article rapide, nous avons montré comment convertir des chiffres romains et arabes.

Nous avons utilisé unenum pour représenter l'ensemble des chiffres romains et nous avons créé une classe utilitaire pour effectuer les conversions.

L'implémentation complète et tous les tests peuvent être trouvésover on GitHub.