web-dev-qa-db-fra.com

Conversion d'entiers en chiffres romains - Java

C'est un devoir qui me pose problème.

Je dois faire un convertisseur entier en chiffres romains en utilisant une méthode. Plus tard, je dois ensuite utiliser le programme pour écrire de 1 à 3999 en chiffres romains, le codage en dur est donc terminé. Mon code ci-dessous est très dépouillé; c'est une boucle d'E/S de base avec un moyen de sortir en utilisant un paquetage pour getIntegerFromUser que nous avons créé en classe.

Existe-t-il un moyen d'attribuer des valeurs à Strings, puis de les additionner lorsque j'appelle la méthode?

Mise à jour: J'ai reçu un pseudo code de mon professeur pour m'aider et, même si je comprends ce qu'il essaie de dire, j'ai un problème avec les ifs. Aurai-je besoin de beaucoup, de nombreuses instructions if pour que mon convertisseur gère correctement la mise en forme des chiffres romains ou y a-t-il une manière de le faire avec plus d'efficacité? J'ai mis à jour mon code pour refléter ma méthode de marque de réservation.

Mise à jour (28 octobre 2012): Je l'ai fait fonctionner. Voici ce que j'ai fini par utiliser: 

public static String IntegerToRomanNumeral(int input) {
    if (input < 1 || input > 3999)
        return "Invalid Roman Number Value";
    String s = "";
    while (input >= 1000) {
        s += "M";
        input -= 1000;        }
    while (input >= 900) {
        s += "CM";
        input -= 900;
    }
    while (input >= 500) {
        s += "D";
        input -= 500;
    }
    while (input >= 400) {
        s += "CD";
        input -= 400;
    }
    while (input >= 100) {
        s += "C";
        input -= 100;
    }
    while (input >= 90) {
        s += "XC";
        input -= 90;
    }
    while (input >= 50) {
        s += "L";
        input -= 50;
    }
    while (input >= 40) {
        s += "XL";
        input -= 40;
    }
    while (input >= 10) {
        s += "X";
        input -= 10;
    }
    while (input >= 9) {
        s += "IX";
        input -= 9;
    }
    while (input >= 5) {
        s += "V";
        input -= 5;
    }
    while (input >= 4) {
        s += "IV";
        input -= 4;
    }
    while (input >= 1) {
        s += "I";
        input -= 1;
    }    
    return s;
}
55
user1752197

Une implémentation compacte utilisant Java TreeMap et récursivité:

import Java.util.TreeMap;

public class RomanNumber {

    private final static TreeMap<Integer, String> map = new TreeMap<Integer, String>();

    static {

        map.put(1000, "M");
        map.put(900, "CM");
        map.put(500, "D");
        map.put(400, "CD");
        map.put(100, "C");
        map.put(90, "XC");
        map.put(50, "L");
        map.put(40, "XL");
        map.put(10, "X");
        map.put(9, "IX");
        map.put(5, "V");
        map.put(4, "IV");
        map.put(1, "I");

    }

    public final static String toRoman(int number) {
        int l =  map.floorKey(number);
        if ( number == l ) {
            return map.get(number);
        }
        return map.get(l) + toRoman(number-l);
    }

}

Essai:

public void testRomanConversion() {

    for (int i = 1; i<= 100; i++) {
        System.out.println(i+"\t =\t "+RomanNumber.toRoman(i));
    }

}
103

Utilisez ces bibliothèques:

import Java.util.LinkedHashMap;
import Java.util.Map;

Le code:

  public static String RomanNumerals(int Int) {
    LinkedHashMap<String, Integer> roman_numerals = new LinkedHashMap<String, Integer>();
    roman_numerals.put("M", 1000);
    roman_numerals.put("CM", 900);
    roman_numerals.put("D", 500);
    roman_numerals.put("CD", 400);
    roman_numerals.put("C", 100);
    roman_numerals.put("XC", 90);
    roman_numerals.put("L", 50);
    roman_numerals.put("XL", 40);
    roman_numerals.put("X", 10);
    roman_numerals.put("IX", 9);
    roman_numerals.put("V", 5);
    roman_numerals.put("IV", 4);
    roman_numerals.put("I", 1);
    String res = "";
    for(Map.Entry<String, Integer> entry : roman_numerals.entrySet()){
      int matches = Int/entry.getValue();
      res += repeat(entry.getKey(), matches);
      Int = Int % entry.getValue();
    }
    return res;
  }
  public static String repeat(String s, int n) {
    if(s == null) {
        return null;
    }
    final StringBuilder sb = new StringBuilder();
    for(int i = 0; i < n; i++) {
        sb.append(s);
    }
    return sb.toString();
  }

Test du code:

  for (int i = 1;i<256;i++) {
    System.out.println("i="+i+" -> "+RomanNumerals(i));
  }

Le résultat:

  i=1 -> I
  i=2 -> II
  i=3 -> III
  i=4 -> IV
  i=5 -> V
  i=6 -> VI
  i=7 -> VII
  i=8 -> VIII
  i=9 -> IX
  i=10 -> X
  i=11 -> XI
  i=12 -> XII
  i=13 -> XIII
  i=14 -> XIV
  i=15 -> XV
  i=16 -> XVI
  i=17 -> XVII
  i=18 -> XVIII
  i=19 -> XIX
  i=20 -> XX
  i=21 -> XXI
  i=22 -> XXII
  i=23 -> XXIII
  i=24 -> XXIV
  i=25 -> XXV
  i=26 -> XXVI
  i=27 -> XXVII
  i=28 -> XXVIII
  i=29 -> XXIX
  i=30 -> XXX
  i=31 -> XXXI
  i=32 -> XXXII
  i=33 -> XXXIII
  i=34 -> XXXIV
  i=35 -> XXXV
  i=36 -> XXXVI
  i=37 -> XXXVII
  i=38 -> XXXVIII
  i=39 -> XXXIX
  i=40 -> XL
  i=41 -> XLI
  i=42 -> XLII
  i=43 -> XLIII
  i=44 -> XLIV
  i=45 -> XLV
  i=46 -> XLVI
  i=47 -> XLVII
  i=48 -> XLVIII
  i=49 -> XLIX
  i=50 -> L
  i=51 -> LI
  i=52 -> LII
  i=53 -> LIII
  i=54 -> LIV
  i=55 -> LV
  i=56 -> LVI
  i=57 -> LVII
  i=58 -> LVIII
  i=59 -> LIX
  i=60 -> LX
  i=61 -> LXI
  i=62 -> LXII
  i=63 -> LXIII
  i=64 -> LXIV
  i=65 -> LXV
  i=66 -> LXVI
  i=67 -> LXVII
  i=68 -> LXVIII
  i=69 -> LXIX
  i=70 -> LXX
  i=71 -> LXXI
  i=72 -> LXXII
  i=73 -> LXXIII
  i=74 -> LXXIV
  i=75 -> LXXV
  i=76 -> LXXVI
  i=77 -> LXXVII
  i=78 -> LXXVIII
  i=79 -> LXXIX
  i=80 -> LXXX
  i=81 -> LXXXI
  i=82 -> LXXXII
  i=83 -> LXXXIII
  i=84 -> LXXXIV
  i=85 -> LXXXV
  i=86 -> LXXXVI
  i=87 -> LXXXVII
  i=88 -> LXXXVIII
  i=89 -> LXXXIX
  i=90 -> XC
  i=91 -> XCI
  i=92 -> XCII
  i=93 -> XCIII
  i=94 -> XCIV
  i=95 -> XCV
  i=96 -> XCVI
  i=97 -> XCVII
  i=98 -> XCVIII
  i=99 -> XCIX
  i=100 -> C
  i=101 -> CI
  i=102 -> CII
  i=103 -> CIII
  i=104 -> CIV
  i=105 -> CV
  i=106 -> CVI
  i=107 -> CVII
  i=108 -> CVIII
  i=109 -> CIX
  i=110 -> CX
  i=111 -> CXI
  i=112 -> CXII
  i=113 -> CXIII
  i=114 -> CXIV
  i=115 -> CXV
  i=116 -> CXVI
  i=117 -> CXVII
  i=118 -> CXVIII
  i=119 -> CXIX
  i=120 -> CXX
  i=121 -> CXXI
  i=122 -> CXXII
  i=123 -> CXXIII
  i=124 -> CXXIV
  i=125 -> CXXV
  i=126 -> CXXVI
  i=127 -> CXXVII
  i=128 -> CXXVIII
  i=129 -> CXXIX
  i=130 -> CXXX
  i=131 -> CXXXI
  i=132 -> CXXXII
  i=133 -> CXXXIII
  i=134 -> CXXXIV
  i=135 -> CXXXV
  i=136 -> CXXXVI
  i=137 -> CXXXVII
  i=138 -> CXXXVIII
  i=139 -> CXXXIX
  i=140 -> CXL
  i=141 -> CXLI
  i=142 -> CXLII
  i=143 -> CXLIII
  i=144 -> CXLIV
  i=145 -> CXLV
  i=146 -> CXLVI
  i=147 -> CXLVII
  i=148 -> CXLVIII
  i=149 -> CXLIX
  i=150 -> CL
  i=151 -> CLI
  i=152 -> CLII
  i=153 -> CLIII
  i=154 -> CLIV
  i=155 -> CLV
  i=156 -> CLVI
  i=157 -> CLVII
  i=158 -> CLVIII
  i=159 -> CLIX
  i=160 -> CLX
  i=161 -> CLXI
  i=162 -> CLXII
  i=163 -> CLXIII
  i=164 -> CLXIV
  i=165 -> CLXV
  i=166 -> CLXVI
  i=167 -> CLXVII
  i=168 -> CLXVIII
  i=169 -> CLXIX
  i=170 -> CLXX
  i=171 -> CLXXI
  i=172 -> CLXXII
  i=173 -> CLXXIII
  i=174 -> CLXXIV
  i=175 -> CLXXV
  i=176 -> CLXXVI
  i=177 -> CLXXVII
  i=178 -> CLXXVIII
  i=179 -> CLXXIX
  i=180 -> CLXXX
  i=181 -> CLXXXI
  i=182 -> CLXXXII
  i=183 -> CLXXXIII
  i=184 -> CLXXXIV
  i=185 -> CLXXXV
  i=186 -> CLXXXVI
  i=187 -> CLXXXVII
  i=188 -> CLXXXVIII
  i=189 -> CLXXXIX
  i=190 -> CXC
  i=191 -> CXCI
  i=192 -> CXCII
  i=193 -> CXCIII
  i=194 -> CXCIV
  i=195 -> CXCV
  i=196 -> CXCVI
  i=197 -> CXCVII
  i=198 -> CXCVIII
  i=199 -> CXCIX
  i=200 -> CC
  i=201 -> CCI
  i=202 -> CCII
  i=203 -> CCIII
  i=204 -> CCIV
  i=205 -> CCV
  i=206 -> CCVI
  i=207 -> CCVII
  i=208 -> CCVIII
  i=209 -> CCIX
  i=210 -> CCX
  i=211 -> CCXI
  i=212 -> CCXII
  i=213 -> CCXIII
  i=214 -> CCXIV
  i=215 -> CCXV
  i=216 -> CCXVI
  i=217 -> CCXVII
  i=218 -> CCXVIII
  i=219 -> CCXIX
  i=220 -> CCXX
  i=221 -> CCXXI
  i=222 -> CCXXII
  i=223 -> CCXXIII
  i=224 -> CCXXIV
  i=225 -> CCXXV
  i=226 -> CCXXVI
  i=227 -> CCXXVII
  i=228 -> CCXXVIII
  i=229 -> CCXXIX
  i=230 -> CCXXX
  i=231 -> CCXXXI
  i=232 -> CCXXXII
  i=233 -> CCXXXIII
  i=234 -> CCXXXIV
  i=235 -> CCXXXV
  i=236 -> CCXXXVI
  i=237 -> CCXXXVII
  i=238 -> CCXXXVIII
  i=239 -> CCXXXIX
  i=240 -> CCXL
  i=241 -> CCXLI
  i=242 -> CCXLII
  i=243 -> CCXLIII
  i=244 -> CCXLIV
  i=245 -> CCXLV
  i=246 -> CCXLVI
  i=247 -> CCXLVII
  i=248 -> CCXLVIII
  i=249 -> CCXLIX
  i=250 -> CCL
  i=251 -> CCLI
  i=252 -> CCLII
  i=253 -> CCLIII
  i=254 -> CCLIV
  i=255 -> CCLV
28
chepe lucho

De Java Notes 6.0 website:

      /**
       * An object of type RomanNumeral is an integer between 1 and 3999.  It can
       * be constructed either from an integer or from a string that represents
       * a Roman numeral in this range.  The function toString() will return a
       * standardized Roman numeral representation of the number.  The function
       * toInt() will return the number as a value of type int.
       */
      public class RomanNumeral {

         private final int num;   // The number represented by this Roman numeral.

         /* The following arrays are used by the toString() function to construct
            the standard Roman numeral representation of the number.  For each i,
            the number numbers[i] is represented by the corresponding string, letters[i].
         */

         private static int[]    numbers = { 1000,  900,  500,  400,  100,   90,  
                                               50,   40,   10,    9,    5,    4,    1 };

         private static String[] letters = { "M",  "CM",  "D",  "CD", "C",  "XC",
                                             "L",  "XL",  "X",  "IX", "V",  "IV", "I" };

         /**
          * Constructor.  Creates the Roman number with the int value specified
          * by the parameter.  Throws a NumberFormatException if arabic is
          * not in the range 1 to 3999 inclusive.
          */
         public RomanNumeral(int arabic) {
            if (arabic < 1)
               throw new NumberFormatException("Value of RomanNumeral must be positive.");
            if (arabic > 3999)
               throw new NumberFormatException("Value of RomanNumeral must be 3999 or less.");
            num = arabic;
         }


         /*
          * Constructor.  Creates the Roman number with the given representation.
          * For example, RomanNumeral("xvii") is 17.  If the parameter is not a
          * legal Roman numeral, a NumberFormatException is thrown.  Both upper and
          * lower case letters are allowed.
          */
         public RomanNumeral(String roman) {

            if (roman.length() == 0)
               throw new NumberFormatException("An empty string does not define a Roman numeral.");

            roman = roman.toUpperCase();  // Convert to upper case letters.

            int i = 0;       // A position in the string, roman;
            int arabic = 0;  // Arabic numeral equivalent of the part of the string that has
                             //    been converted so far.

            while (i < roman.length()) {

               char letter = roman.charAt(i);        // Letter at current position in string.
               int number = letterToNumber(letter);  // Numerical equivalent of letter.

               i++;  // Move on to next position in the string

               if (i == roman.length()) {
                     // There is no letter in the string following the one we have just processed.
                     // So just add the number corresponding to the single letter to arabic.
                  arabic += number;
               }
               else {
                     // Look at the next letter in the string.  If it has a larger Roman numeral
                     // equivalent than number, then the two letters are counted together as
                     // a Roman numeral with value (nextNumber - number).
                  int nextNumber = letterToNumber(roman.charAt(i));
                  if (nextNumber > number) {
                       // Combine the two letters to get one value, and move on to next position in string.
                     arabic += (nextNumber - number);
                     i++;
                  }
                  else {
                       // Don't combine the letters.  Just add the value of the one letter onto the number.
                     arabic += number;
                  }
               }

            }  // end while

            if (arabic > 3999)
               throw new NumberFormatException("Roman numeral must have value 3999 or less.");

            num = arabic;

         } // end constructor


         /**
          * Find the integer value of letter considered as a Roman numeral.  Throws
          * NumberFormatException if letter is not a legal Roman numeral.  The letter 
          * must be upper case.
          */
         private int letterToNumber(char letter) {
            switch (letter) {
               case 'I':  return 1;
               case 'V':  return 5;
               case 'X':  return 10;
               case 'L':  return 50;
               case 'C':  return 100;
               case 'D':  return 500;
               case 'M':  return 1000;
               default:   throw new NumberFormatException(
                            "Illegal character \"" + letter + "\" in Roman numeral");
            }
         }


         /**
          * Return the standard representation of this Roman numeral.
          */
         public String toString() {
            String roman = "";  // The roman numeral.
            int N = num;        // N represents the part of num that still has
                                //   to be converted to Roman numeral representation.
            for (int i = 0; i < numbers.length; i++) {
               while (N >= numbers[i]) {
                  roman += letters[i];
                  N -= numbers[i];
               }
            }
            return roman;
         }


         /**
          * Return the value of this Roman numeral as an int.
          */
         public int toInt() {
            return num;
         }


      }
25
Mordechai

Il existe en réalité une autre façon de considérer ce problème, non pas comme un problème de nombre, mais comme un problème unaire, commençant par le caractère de base des nombres romains, "I". Donc, nous représentons le nombre avec seulement I, puis nous remplaçons les caractères dans la valeur croissante des caractères romains. 

public String getRomanNumber(int number) {
    return join("", nCopies(number, "I"))
            .replace("IIIII", "V")
            .replace("IIII", "IV")
            .replace("VV", "X")
            .replace("VIV", "IX")
            .replace("XXXXX", "L")
            .replace("XXXX", "XL")
            .replace("LL", "C")
            .replace("LXL", "XC")
            .replace("CCCCC", "D")
            .replace("CCCC", "CD")
            .replace("DD", "M")
            .replace("DCD", "CM");
}

J'aime particulièrement cette méthode pour résoudre ce problème plutôt que d’utiliser beaucoup de boucles if et while, ou de tables. C’est aussi une solution intuitive lorsque vous envisagez le problème et non comme un problème de nombre.

19

J'ai écrit une solution très simple. Tout ce que nous avons à faire est de diviser et de trouver combien de fois une lettre particulière (ou une combinaison de lettres se produit) et de l'ajouter à l'objet StringBuilder sb. Nous devrions également garder une trace du nombre restant (num).

public static String intToRoman(int num) {
    StringBuilder sb = new StringBuilder();
    int times = 0;
    String[] romans = new String[] { "I", "IV", "V", "IX", "X", "XL", "L",
            "XC", "C", "CD", "D", "CM", "M" };
    int[] ints = new int[] { 1, 4, 5, 9, 10, 40, 50, 90, 100, 400, 500,
            900, 1000 };
    for (int i = ints.length - 1; i >= 0; i--) {
        times = num / ints[i];
        num %= ints[i];
        while (times > 0) {
            sb.append(romans[i]);
            times--;
        }
    }
    return sb.toString();
} 
10
Adilli Adil

J'aime la réponse d'André Kramer Orten, très élégante, j'aime particulièrement le fait qu'il évite les boucles, j'ai alors pensé à une autre façon de le gérer, tout en évitant les boucles.

Il utilise la division entière et le modulo sur l’entrée pour sélectionner l’index correct dans un ensemble codé en dur de tableaux de chaînes pour chaque type d’unité.

La bonne chose ici est que vous pouvez spécifier des conversions exactes selon que vous voulez la forme numérique additive ou soustractive, c’est-à-dire IIII vs IV. Ici, j'utilise la "forme soustractive" pour tous les nombres de la forme 5x-1 (4,9,14,19,40,90, etc.)

Il serait également trivial d’étendre ceci pour permettre des nombres plus grands en étendant simplement le tableau des milliers avec d’autres formes additives ou soustractives, c’est-à-dire "IV", "V" ou "MMMM"

Pour les points bonus, je m'assure en fait que le paramètre numéro est compris dans la plage donnée pour le problème.

public class RomanNumeralGenerator {
    static final int MIN_VALUE = 1;
    static final int MAX_VALUE = 3999;
    static final String[] RN_M = {"", "M", "MM", "MMM"};
    static final String[] RN_C = {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"};
    static final String[] RN_X = {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"};
    static final String[] RN_I = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"};

    public String generate(int number) {
        if (number < MIN_VALUE || number > MAX_VALUE) {
            throw new IllegalArgumentException(
                    String.format(
                            "The number must be in the range [%d, %d]",
                            MIN_VALUE,
                            MAX_VALUE
                    )
            );
        }

        return new StringBuilder()
                .append(RN_M[number / 1000])
                .append(RN_C[number % 1000 / 100])
                .append(RN_X[number % 100 / 10])
                .append(RN_I[number % 10])
                .toString();
    }
}
8
Fraser

Je pense que ma solution est l'une des plus concises:

private static String convertToRoman(int mInt) {
    String[] rnChars = { "M",  "CM", "D", "C",  "XC", "L",  "X", "IX", "V", "I" };
    int[] rnVals = {  1000, 900, 500, 100, 90, 50, 10, 9, 5, 1 };
    String retVal = "";

    for (int i = 0; i < rnVals.length; i++) {
        int numberInPlace = mInt / rnVals[i];
        if (numberInPlace == 0) continue;
        retVal += numberInPlace == 4 && i > 0? rnChars[i] + rnChars[i - 1]:
            new String(new char[numberInPlace]).replace("\0",rnChars[i]);
        mInt = mInt % rnVals[i];
    }
    return retVal;
}
7
Dan Rothman
String convert(int i){

    String ones = "";
    String tens = "";
    String hundreds = "";
    String thousands = "";
    String result ;

    boolean error = false;

    Vector v = new Vector();

    //assign passed integer to temporary value temp
    int temp=i;

    //flags an error if number is greater than 3999
    if (temp >=4000) {
       error = true;
    }

    /*loops while temp can no more be divided by 10.
        Lets say i = 3254, then temp is also 3254 at line 14.

                           3254 
          3254/10 = 25    /   \ 3254%10 = 4
                         /     \
    now temp = 25       325     4  - here 4 is added to the vector v's 0th index.
                        / \
    now temp = 32     32   5  - here 5 is added to the vector v's 1st index.
                     /  \
    now temp = 3    3    2  - here 2 is added to the vector v's 2nd index, and loop exits
                   / \        since temp/10 = 0
                  0   3  - here 3 is not added to the vector v's 3rd index as loop exits when
                            temp/10 = 0.


    */
    while (temp/10 != 0) {
        if (temp / 10 != 0 && temp <4000) {
            v.add(temp%10);
            temp = temp / 10;
        }else {     
            break;
        }
    }

    //therefore you have to add temp one last time to the vector
    v.add(temp);

    //as in the example now you have 4,5,2,3 respectively in v's 0,1,2,3 indices.


    for (int j = 0; j < v.size(); j++) {

        //you see that v's 0th index has number of ones. So make them roman ones here.
        if (j==0) {
            switch (v.get(0).toString()){
                case "0" : ones = ""; break;
                case "1" : ones = "I"; break;
                case "2" : ones = "II"; break;
                case "3" : ones = "III"; break;
                case "4" : ones = "IV"; break;
                case "5" : ones = "V"; break;
                case "6" : ones = "VI"; break;
                case "7" : ones = "VII"; break;
                case "8" : ones = "VIII"; break;
                case "9" : ones = "IX"; break;
            }


            //in the second iteration of the loop (when j==1) 
            //index 1 of v is checked. Now you understand that v's 1st index
            //has the tens
        } else if (j == 1) {
            switch (v.get(1).toString()){
                case "0" : tens = ""; break;
                case "1" : tens = "X"; break;
                case "2" : tens = "XX"; break;
                case "3" : tens = "XXX"; break;
                case "4" : tens = "XL"; break;
                case "5" : tens = "L"; break;
                case "6" : tens = "LX"; break;
                case "7" : tens = "LXX"; break;
                case "8" : tens = "LXXX"; break;
                case "9" : tens = "XC"; break;
            }
        } else if(j == 2){  //and hundreds
            switch (v.get(2).toString()){
                case "0" : hundreds = ""; break;
                case "1" : hundreds = "C"; break;
                case "2" : hundreds = "CC"; break;
                case "3" : hundreds = "CCC"; break;
                case "4" : hundreds = "CD"; break;
                case "5" : hundreds = "D"; break;
                case "6" : hundreds = "DC"; break;
                case "7" : hundreds = "DCC"; break;
                case "8" : hundreds = "DCCC"; break;
                case "9" : hundreds = "CM"; break;
            }
        }   else if(j == 3){ //and finally thousands.
            switch (v.get(3).toString()){           
                case "0" : thousands = ""; break;
                case "1" : thousands = "M"; break;
                case "2" : thousands = "MM"; break;
                case "3" : thousands = "MMM"; break;

            }
        } 
    }



    if (error) {
       result = "Error!";
    }else{
        result = thousands + hundreds + tens + ones;
    }

    return result;

}
3
Lahiru Kavinda

Je suis curieux de savoir comment cela va se terminer. Je commencerais à regarder dans la cartographie 1,2,3,5,6,7,8,9,10 à I, II, III, IV, V, VI, VII, VII, IX, X ... alors vous pourrait examiner la règle des chiffres romains: I, II, III sont créés par concaténation V, X, L, C, D et M sont des symboles pour 5, 10, 50, 100, 500 et 1000 Les Romains pensaient pouvoir économiser de la place en écrivant des nombres en écrivant par exemple IIII pour 4 utilise IV (ce qui signifie: 5 moins 1 ...) Vous voudrez peut-être examiner ces règles, par exemple. at http://en.wikipedia.org/wiki/Roman_numerals et capturez-les dans du code, par exemple. dans une classe "RomanNumbers" Si vous voulez tricher, suivez le lien http://www.moxlotus.alternatifs.eu/programmation-converter.html

2
Wolfgang Fahl

Ma solution est dans la fonction getRoman:

public  String getRoman(int number) {

    String riman[] = {"M","XM","CM","D","XD","CD","C","XC","L","XL","X","IX","V","IV","I"};
    int arab[] = {1000, 990, 900, 500, 490, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
    StringBuilder result = new StringBuilder();
    int i = 0;
    while (number > 0 || arab.length == (i - 1)) {
        while ((number - arab[i]) >= 0) {
            number -= arab[i];
            result.append(riman[i]);
        }
        i++;
    }
    return result.toString();
}
2
gizmo16
private static String toRoman(int n) {
    String[] romanNumerals = { "M",  "CM", "D", "CD", "C", "XC", "L",  "X", "IX", "V", "I" };
    int[] romanNumeralNums = {  1000, 900, 500,  400 , 100,  90,  50,   10,    9,   5,   1 };
    String finalRomanNum = "";

    for (int i = 0; i < romanNumeralNums.length; i ++) {
            int currentNum = n /romanNumeralNums[i];
            if (currentNum==0) {
                continue;
            }

            for (int j = 0; j < currentNum; j++) {
                finalRomanNum +=romanNumerals[i];
            }

            n = n%romanNumeralNums[i];
    }
    return finalRomanNum;
}
2
Mark F

J'ai remarqué qu'il est assez facile de traduire d'un nombre entier en chiffres romains, car il y a toujours une sorte de 1, 5 et 10 pour chaque chiffre (c'est-à-dire I, V et X pour 1-10, X, L et C pour 10-100, etc.) C'est pourquoi j'ai créé un tableau de chiffres romains pour obtenir le bon lettre de.

Dans mon exemple, je numérise un chiffre à la fois, en utilisant l'opérateur modulo pour obtenir le dernier chiffre à chaque fois. Ensuite, je forme le chiffre romain à partir du chiffre actuel à l'intérieur d'une instruction switch, en l'ajoutant au début de asRomanNumerals String. Une fois le chiffre traduit, il est supprimé du nombre et l'index utilisé pour rechercher une lettre dans un tableau est augmenté de deux (IVX -> XLC).

public static void main(String[] args) {

    // number is the one to be translated into Roman Numerals
    int number = 2345;
    number = Math.min(3999, Math.max(1, number)); // wraps number between 1-3999
    String asRomanNumerals = "";

    // Array including numerals in ascending order
    String[] RN = {"I", "V", "X", "L", "C", "D", "M" };
    int i = 0; // Index used to keep track which digit we are translating
    while (number > 0) {
        switch(number % 10) {
        case 1: asRomanNumerals = RN[i] + asRomanNumerals; break;
        case 2: asRomanNumerals = RN[i] + RN[i] + asRomanNumerals; break;
        case 3: asRomanNumerals = RN[i] + RN[i] + RN[i] + asRomanNumerals; break;
        case 4: asRomanNumerals = RN[i] + RN[i + 1] + asRomanNumerals; break;
        case 5: asRomanNumerals = RN[i + 1] + asRomanNumerals; break;
        case 6: asRomanNumerals = RN[i + 1] + RN[i] + asRomanNumerals; break;
        case 7: asRomanNumerals = RN[i + 1] + RN[i] + RN[i] + asRomanNumerals; break;
        case 8: asRomanNumerals = RN[i + 1] + RN[i] + RN[i] + RN[i] +asRomanNumerals; break;
        case 9: asRomanNumerals = RN[i] + RN[i + 2] + asRomanNumerals; break;
        }
        number = (int) number / 10;
        i += 2;
    }
    System.out.println(asRomanNumerals);
}
2
Aleksi Sjöberg

Voici les résultats de mes devoirs. Cela ne garantit pas que l'entrée est dans la bonne plage et je devrais probablement utiliser StringBuilder (le temps que je le cherche!) Et ce n'est pas une méthode unique. Mais si quelqu'un lit jusqu'ici, j'apprécierais à la fois les commentaires positifs et négatifs!

import Java.util.Scanner;
    /**
     *Main() allows user input and tests 1-3999
     *toRoman() breaks the number down into digits and passes them to romanLogic()
     *romanLogic() converts each digit into a the numerals that represent it.
     */
    public class RomanNumerals
    {
        public static void main(String args[]){
            Scanner in = new Scanner(System.in);
            System.out.print("give us an integer < 4000: ");        
            System.out.println("the roman numeral version is: " + toRoman(in.nextInt()));
            for (int i = 1; i<=3999; i++){
                System.out.println(i +" === "+ toRoman(i));
            }
        }
        public static String toRoman(int i){
            String output = "";
            int digits = i%10;
            int tens = (i%100)/10;
            int hundreds = (i%1000)/100;
            int thousands = (i%10000)/1000;
            return (romanLogic(thousands, "M","","")+
                    romanLogic(hundreds,"C","D","M")+
                    romanLogic(tens,"X","L","C")+
                    romanLogic(digits,"I","V","X"));
        }
        public static String romanLogic(int i, String ones, String fives, String tens){
            String result = "";
            if (i == 0){
                return result;
            } else {
                if ((i>=4)&&(i<=8)){                
                    result += fives;
                }
                if (i==9){
                    result += tens;
                }
                if(i%5 < 4){
                    while(i%5 > 0){
                        result += ones;
                        i--;
                    }
                }
                if(i%5 == 4){
                    result = ones + result;
                }
            }
            return result;
        }    
    }
2
Luke Matthews

Je pense que si vous étudiez la théorie des chiffres romains avec soin, vous n'avez pas besoin de mappages pour les nombres 4,9,40, etc., car la théorie nous indique si le chiffre romain est IV = 5-1 = 4, donc lorsque le préfixe est inférieur à le numéro suivant dans ce cas, vous devez soustraire l'ancien numéro du numéro suivant pour obtenir la valeur réelle et voici ce que j'ai incorporé dans mon code pour le problème, jetez un coup d'œil et signalez les erreurs éventuelles, j'ai suivi tableau pour concevoir ma logique - http://literacy.kent.edu/Minigrants/Cinci/romanchart.htm

import Java.util.Set;
import Java.io.File;
import Java.util.HashMap;
import Java.util.HashSet;
import Java.io.FileReader;
import Java.io.IOException;
import Java.io.BufferedReader;

public class RomanStringToIntegerConversion {
    public static void main(String[] args) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in)));
        String[] romanString = br.readLine().split("");

        HashMap<String, Integer> romanToIntegerMap = new HashMap<String, Integer>();
        romanToIntegerMap.put("I", 1);
        romanToIntegerMap.put("V", 5);
        romanToIntegerMap.put("X", 10);
        romanToIntegerMap.put("L", 50);
        romanToIntegerMap.put("C", 100);
        romanToIntegerMap.put("D", 500);
        romanToIntegerMap.put("M", 1000);

        int numLength = romanString.length;
        Set<Integer> lessIndices = new HashSet<Integer>();

        for(int i = 0; i < numLength; ++i){
            if(i+1 < numLength){
                if(romanToIntegerMap.get(romanString[i]) < romanToIntegerMap.get(romanString[i+1]))
                    lessIndices.add(i);
            }
        }

        int num = 0;
        for(int i = 0; i < numLength;){
            if(!lessIndices.contains(i)){
                num = num + romanToIntegerMap.get(romanString[i]);
                ++i;
            }
            else{
                num = num + romanToIntegerMap.get(romanString[i+1]) - romanToIntegerMap.get(romanString[i]);
                i+=2;
            }
        }
        System.out.println("The integer representation of the roman numeral is : " + num);
    }
}
2
AnkitSablok
enum Numeral {
        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);
        int weight;

        Numeral(int weight) {
            this.weight = weight;
        }
    };

    public static String roman(long n) {

        if( n <= 0) {
            throw new IllegalArgumentException();
        }

        StringBuilder buf = new StringBuilder();

        final Numeral[] values = Numeral.values();
        for (int i = values.length - 1; i >= 0; i--) {
            while (n >= values[i].weight) {
                buf.append(values[i]);
                n -= values[i].weight;
            }
        }
        return buf.toString();
    }

    public static void test(long n) {
        System.out.println(n + " = " + roman(n));
    }

    public static void main(String[] args) {
        test(1999);
        test(25);
        test(944);
        test(0);
    }

Juste pour suivre la technologie, voici une version de Java 8 utilisant des flux et un collecteur personnalisé, éliminant ainsi le besoin de boucles ou d'instructions if:

import Java.util.Arrays;
import Java.util.Collections;
import Java.util.Set;
import Java.util.function.BiConsumer;
import Java.util.function.BinaryOperator;
import Java.util.function.Function;
import Java.util.function.Supplier;
import Java.util.stream.Collector;
import Java.util.stream.IntStream;

public class RomanNumeral {

    public static void main(String arg[]) {
        IntStream.range(1, 4000).forEach(value -> System.out.println( Arrays.stream(Mark.values()).collect(new MarkCollector<Mark>(value)).toString()));
    }

    enum Mark {
        M(1000), CM(900), D(500), CD(400), C(100), XC(90), L(50), XL(40), X(10), IX(9), V(5), IV(4), I(1);

        private final int value;

        private Mark(int value) { this.value = value; }

        public int value() { return value; }
    }

    static class MarkCollector<T extends Mark> implements Collector<T, StringBuilder, StringBuilder> {

        private final int[] valueholder = new int[1];

        MarkCollector(int value) { valueholder[0] = value; }

        @Override
        public Supplier<StringBuilder> supplier() { return () -> StringBuilder::new; }

        @Override
        public BiConsumer<StringBuilder, T> accumulator() {
            return (builder, mark) -> {
                builder.append(String.join("", Collections.nCopies(valueholder[0] / mark.value(), mark.name())));
                valueholder[0] = valueholder[0] % mark.value();
            };
        }

        @Override
        public BinaryOperator<StringBuilder> combiner() { return null; }

        @Override
        public Function<StringBuilder, StringBuilder> finisher() { return Function.identity(); }

        @Override
        public Set<Characteristics> characteristics() { return Collections.singleton(Characteristics.IDENTITY_FINISH); }
    }
}
0
Matthew Flynn

La solution la plus simple:

public class RomanNumerals {

    private static int [] arabic = {50, 40, 10, 9, 5, 4, 1};

    private static String [] roman = {"L", "XL", "X", "IX", "V", "IV", "I"};

    public static String convert(int arabicNumber) {

        StringBuilder romanNumerals = new StringBuilder();
        int remainder = arabicNumber;

        for (int i=0;i<arabic.length;i++) {

            while (remainder >= arabic[i]) {
                romanNumerals.append(roman[i]);
                remainder -= arabic[i];
            }
        }

        return romanNumerals.toString();
    }
}
0
wild_nothing

Commencez par diviser le nombre en facteurs décimaux tels que 995 = 900 + 90 + 5, puis convertissez chaque facteur récursivement.

public class IntegerToRoman {
  private Map<Integer, String> romanChars = new HashMap<>();

  public IntegerToRoman() {
    romanChars.put(1, "I");
    romanChars.put(5, "V");
    romanChars.put(10, "X");
    romanChars.put(50, "L");
    romanChars.put(100, "C");
    romanChars.put(500, "D");
    romanChars.put(1000, "M");
    romanChars.put(5000, "V|");
 }

 public String intToRoman(int num) {
    if (num == 0) {
        return "";
    }
    int decimalFact = 0;
    StringBuilder result = new StringBuilder();
    for (int i = (int)Math.log10(num); i >= 0; i--) {
        int divisor = (int) Math.pow(10, i);
        decimalFact = num - num % divisor;
        result.append(convertDecimalFact(decimalFact));
        num = num % divisor;
    }
    return result.toString();
}

private String convertDecimalFact(int decimalFact){
  if(decimalFact == 0){return "";}
  int[] keyArray = romanChars.keySet().stream().mapToInt(key -> key) 
       .sorted().toArray(); 

  for(int i =0 ; i+1<keyArray.length ; i++){
      if( keyArray[i] <= decimalFact && decimalFact<= keyArray[i+1]  ){
         int bigger1stDgt = getLeftMostNum(keyArray[i+1]);
         int decimalFact1stDgt = getLeftMostNum(decimalFact);
         return decimalFact1stDgt >= bigger1stDgt-1 ? 
                intToRoman(keyArray[i+1]-decimalFact)+romanChars.get(keyArray[i+1]): 
                romanChars.get(keyArray[i])+intToRoman(decimalFact - keyArray[i]);
      }
  }      
  return "";
}

private int getLeftMostNum(int number) {
    int oneDgt = Integer.valueOf(Integer.valueOf(number).toString()
                 .substring(0, 0 +1));
    if(number<10){
        return oneDgt;
    }       
    int twoDgts = Integer.valueOf(Integer.valueOf(number).toString()
                  .substring(0, 0 +2));
    return twoDgts==10 ? twoDgts : oneDgt;
}

public static void main(String[] args) {

    IntegerToRoman solution = new IntegerToRoman();
    System.out.format(" Decimal 3 -> Roman %s \n ", solution.intToRoman(3));
    System.out.format("Decimal 4 -> Roman %s \n ", solution.intToRoman(4));
    System.out.format("Decimal 8 -> Roman %s \n ", solution.intToRoman(8));
    System.out.format("Decimal 58 -> Roman %s \n ", solution.intToRoman(58));
    System.out.format("Decimal 344 -> Roman %s \n ", solution.intToRoman(344));
    System.out.format("Decimal 995 -> Roman %s \n ", solution.intToRoman(995));
    System.out.format("Decimal 1994 -> Roman %s \n ", solution.intToRoman(1994));
}

}

La sortie est comme:

Décimal 3 -> romain III

Décimal 4 -> Romain IV

Décimale 8 -> Roman VIII

Décimale 58 -> LVIII romain

Décimal 344 -> CCCXLIV romain

Décimal 995 -> CMXCV romain

Décimal 1994 -> Roman MCMXCIV

0
ShayneR

Je l'ai fait avant trois ans, peut-être que cela vous aide: 

public class ToRoman
{

    public static String toRoman(int number)
    {
        StringBuilder br = new StringBuilder("");
        while(number!=0)
        {
            while(number>=1000)
            {
                br.append("M");
                number-=1000;   
            }
            while(number>=900)
            {
                br.append("CM");
                number-=900;    
            }
            while(number>=500)
            {
                br.append("D");
                number-=500;    
            }
            while(number>=400)
            {
                br.append("CD");
                number-=400;    
            }
            while(number>=100)
            {
                br.append("C");
                number-=100;    
            }
            while(number>=90)
            {
                br.append("XC");
                number-=90; 
            }
            while(number>=50)
            {
                br.append("L");
                number-=50; 
            }
            while(number>=40)
            {
                br.append("XL");
                number-=40; 
            }
            while(number>=10)
            {
                br.append("X");
                number-=10; 
            }
            while(number>=9)
            {
                br.append("IX");
                number-=9;  
            }
            while(number>=5)
            {
                br.append("V");
                number-=5;  
            }
            while(number>=4)
            {
                br.append("IV");
                number-=4;  
            }
            while(number>=1)
            {
                br.append("I");
                number-=1;  
            }
        }
        return br.toString();
    }

    public static void main(String [] args)
    {
        System.out.println(toRoman(2000));
    }
}
0
besartm

J'aime utiliser un modèle Chaîne de responsabilité moi-même. Je pense que cela a beaucoup de sens pour ce scénario.

public abstract class NumberChainOfResponsibility {
    protected NumberChainOfResponsibility next;
    protected int decimalValue;
    protected String romanNumeralValue;

    public NumberChainOfResponsibility() {
    }

    public String convert(int decimal) {
        int remainder = decimal;
        StringBuilder numerals = new StringBuilder();
        while (remainder != 0) {
            if (remainder >= this.decimalValue) {
                numerals.append(this.romanNumeralValue);
                remainder -= this.decimalValue;
            } else {
                numerals.append(next.convert(remainder));
                remainder = 0;
            }
        }
        return numerals.toString();
    }
}

Ensuite, je crée une classe qui étend celle-ci à chaque chiffre romain (1/5/10/50/100/500/1000 et 4/9/40/90/400/900).

1000

public class Cor1000 extends NumberChainOfResponsibility {
    public Cor1000() {
        super();
        this.decimalValue = 1000;
        this.romanNumeralValue = "M";
        this.next = new Cor900();
    }
}

1

public class Cor1 extends NumberChainOfResponsibility {
    public Cor1() {
        super();
        this.decimalValue = 1;
        this.romanNumeralValue = "I";
        this.next = null;
    }
}

Une classe servant "d'interface" au convertisseur, exposant une méthode pour convertir un nombre spécifique.

public class Converter {
    private static int MAX_VALUE = 5000;
    private static int MIN_VALUE = 0;
    private static String ERROR_TOO_BIG = "Value is too big!";
    private static String ERROR_TOO_SMALL = "Value is too small!";

    public String convertThisIntToRomanNumerals(int decimal) {
        Cor1000 startingCor = new Cor1000();
        if (decimal >= MAX_VALUE)
            return ERROR_TOO_BIG;
        if (decimal <= MIN_VALUE)
            return ERROR_TOO_SMALL;

        String numeralsWithoutConversion = startingCor.convert(decimal);
        return numeralsWithoutConversion;
    }
}

Et le code client (dans mon cas, un test JUnit).

@Test
public void assertConversionWorks() {
    Assert.assertEquals("MMMMCMXCIX", converter.convertThisIntToRomanNumerals(4999));
    Assert.assertEquals("CMXCIX", converter.convertThisIntToRomanNumerals(999));
    Assert.assertEquals("CMLXXXIX", converter.convertThisIntToRomanNumerals(989));
    Assert.assertEquals("DCXXVI", converter.convertThisIntToRomanNumerals(626));
    Assert.assertEquals("DCXXIV", converter.convertThisIntToRomanNumerals(624));
    Assert.assertEquals("CDXCVIII", converter.convertThisIntToRomanNumerals(498));
    Assert.assertEquals("CXXIII", converter.convertThisIntToRomanNumerals(123));
    Assert.assertEquals("XCIX", converter.convertThisIntToRomanNumerals(99));
    Assert.assertEquals("LI", converter.convertThisIntToRomanNumerals(51));
    Assert.assertEquals("XLIX", converter.convertThisIntToRomanNumerals(49));
}

Voir l’exemple complet sur mon compte Github .

0
Chris Neve

Après avoir fait quelques recherches et analysé les réponses ci-dessus, je me suis retrouvé avec ceci:

package roman;

public class RomanNumbers {


public static final int[] decimal = {1, 4, 5, 9, 10, 40, 50, 90, 100, 400, 500, 900, 1000};
public static final String[] letters = {"I", "IV", "V", "IX", "X", "XL", "L", "XC", "C", "CD", "D", "CM", "M"};

public static String stringToRoman(int num) {
    String roman = "";

    if (num < 1 || num > 3999) {
        System.out.println("Invalid roman number value!");
    }

    while (num > 0) {
        int maxFound = 0;
        for (int i=0; i < decimal.length; i++) {
            if (num >= decimal[i]) {
                maxFound = i;
            }
        }
        roman += letters[maxFound];
        num -= decimal[maxFound];
    }

    return roman;       
  }
}

Les tests unitaires ont également réussi:

package roman;

import static org.junit.Assert.*;

import org.junit.Test;

public class RomanNumbersTest {

@Test
public void testReturn1() {
    String actual = RomanNumbers.stringToRoman(1);
    String expected = "I";
    assertEquals(expected, actual);
}

@Test
public void testReturn5() {
    String actual = RomanNumbers.stringToRoman(5);
    String expected = "V";
    assertEquals(expected, actual);
}

@Test
public void testReturn2() {
    String actual = RomanNumbers.stringToRoman(2);
    String expected = "II";
    assertEquals(expected, actual);
}

@Test
public void testReturn4() {
    String actual = RomanNumbers.stringToRoman(4);
    String expected = "IV";
    assertEquals(expected, actual);
}

@Test
public void testReturn399() {
    String actual = RomanNumbers.stringToRoman(399);
    String expected = "CCCXCIX";
    assertEquals(expected, actual);
}

@Test
public void testReturn3992() {
    String actual = RomanNumbers.stringToRoman(3992);
    String expected = "MMMCMXCII";
    assertEquals(expected, actual);
}
}
0
Igor

Après avoir vu certaines des réponses ici, je devais poster ceci. Je pense que mon algorithme est de loin le plus facile à comprendre et que la perte de performance perdue n’a pas d’importance, même à une échelle relativement grande. J'obéis également aux conventions de codage normalisées par opposition à certains utilisateurs ici.

Temps de conversion moyen: 0.05ms (basé sur la conversion de tous les nombres 1-3999 et divisé par 3999)

public static String getRomanNumeral(int arabicNumber) {

    if (arabicNumber > 0 && arabicNumber < 4000) {

        final LinkedHashMap<Integer, String> numberLimits = 
            new LinkedHashMap<>();

        numberLimits.put(1, "I");
        numberLimits.put(4, "IV");
        numberLimits.put(5, "V");
        numberLimits.put(9, "IX");
        numberLimits.put(10, "X");
        numberLimits.put(40, "XL");
        numberLimits.put(50, "L");
        numberLimits.put(90, "XC");
        numberLimits.put(100, "C");
        numberLimits.put(400, "CD");
        numberLimits.put(500, "D");
        numberLimits.put(900, "CM");
        numberLimits.put(1000, "M");

        String romanNumeral = "";

        while (arabicNumber > 0) {
            int highestFound = 0;
            for (Map.Entry<Integer, String> current : numberLimits.entrySet()){
                if (current.getKey() <= arabicNumber) {
                    highestFound = current.getKey();
                }
            }
            romanNumeral += numberLimits.get(highestFound);
            arabicNumber -= highestFound;
        }

        return romanNumeral;

    } else {
        throw new UnsupportedOperationException(arabicNumber 
            + " is not a valid Roman numeral.");
    }
}

Vous devez d’abord tenir compte du fait que les chiffres romains ne sont compris que dans l’intervalle <1-4000), mais cela peut être résolu par une simple si et une exception levée. Vous pouvez ensuite essayer de trouver le plus grand ensemble de chiffres romains dans un entier donné et, le cas échéant, le soustraire du nombre original et l’ajouter au résultat. Répétez l'opération avec le numéro nouvellement acquis jusqu'à atteindre zéro.

0
Dropout

Cela peut aider:

using System;

using System.Text;

public class Test
{

public static string ToRoman(int number)
{
    StringBuilder br=new StringBuilder("");
    while(number!=0)
    {
        if(number>=1000)
        {
            br.Append("M");
            number-=1000;   
        }
        if(number>=900)
        {
            br.Append("CM");
            number-=900;    
        }
        if(number>=500)
        {
            br.Append("D");
            number-=500;    
        }
        if(number>=400)
        {
            br.Append("CD");
            number-=400;    
        }
        if(number>=100)
        {
            br.Append("C");
            number-=100;    
        }
        if(number>=90)
        {
            br.Append("XC");
            number-=90; 
        }
        if(number>=50)
        {
            br.Append("L");
            number-=50; 
        }
        if(number>=40)
        {
            br.Append("XL");
            number-=40; 
        }
        if(number>=10)
        {
            br.Append("X");
            number-=10; 
        }
        if(number>=9)
        {
            br.Append("IX");
            number-=9;  
        }
        if(number>=5)
        {
            br.Append("V");
            number-=5;  
        }
        if(number>=4)
        {
            br.Append("IV");
            number-=4;  
        }
        if(number>=1)
        {
            br.Append("I");
            number-=1;  
        }
    }
    return br.ToString();
}
public static void Main()
{
    Console.WriteLine(ToRoman(int.Parse(Console.ReadLine())));
}
}
0
Roshan Halwai
private String convertToRoman(int num) {
  String result = "";
  while(num > 0){
    if(num >= 1000){
        result += "M";
        num -= 1000;
    }else if(num >= 900){
        result += "CM";
        num -= 900;
    }
    else if(num >= 500){
        result += "D";
        num -= 500;
    }else if(num >= 400){
        result += "CD";
        num -= 400;
    }else if(num >= 100){
        result += "C";
        num -= 100;
    }else if(num >= 90){
        result += "XC";
        num -= 90;
    }else if(num >= 50){
        result += "L";
        num -= 50;
    }else if(num >= 40){
        result += "XL";
        num -= 40;
    }
    else if(num >= 10){
        result += "X";
        num -= 10;
    }else if(num >= 9){
        result += "IX";
        num -= 9;
    }
    else if(num >= 5){
        result += "V";
        num -= 5;
    }else if(num >= 4){
        result += "IV";
        num -= 4;
    }else if(num >= 1){
        result += "I";
        num -= 1;
    }

    else{
      break;
    }
  }

  return result;
}
0
azibit

Solution alternative basée sur la propre solution du PO utilisant une variable enum. De plus, un analyseur syntaxique et des tests aller-retour sont inclus.

public class RomanNumber {
    public enum Digit {
        M(1000, 3),
        CM(900, 1),
        D(500, 1),
        CD(400, 1),
        C(100, 3),
        XC(90, 1),
        L(50, 1),
        XL(40, 1),
        X(10, 3),
        IX(9, 1),
        V(5, 1),
        IV(4, 1),
        I(1, 3);

        public final int value;
        public final String symbol = name();
        public final int maxArity;

        private Digit(int value, int maxArity) {
            this.value = value;
            this.maxArity = maxArity;
        }
    }

    private static final Digit[] DIGITS = Digit.values();

    public static String of(int number) {
        if (number < 1 || 3999 < number) {
            throw new IllegalArgumentException(String.format(
                    "Roman numbers are only defined for numbers between 1 and 3999 (%d was given)",
                    number
            ));
        }

        StringBuilder sb = new StringBuilder();
        for (Digit digit : DIGITS) {
            int value = digit.value;
            String symbol = digit.symbol;

            while (number >= value) {
                sb.append(symbol);
                number -= value;
            }
        }

        return sb.toString();
    }

    public static int parse(String roman) {
        if (roman.isEmpty()) {
            throw new NumberFormatException("The empty string does not comprise a valid Roman number");
        }

        int number = 0;
        int offset = 0;
        for (Digit digit : DIGITS) {
            int value = digit.value;
            int maxArity = digit.maxArity;
            String symbol = digit.symbol;

            for (int i = 0; i < maxArity && roman.startsWith(symbol, offset); i++) {
                number += value;
                offset += symbol.length();
            }
        }
        if (offset != roman.length()) {
            throw new NumberFormatException(String.format(
                    "The string '%s' does not comprise a valid Roman number",
                    roman
            ));
        }
        return number;
    }

    /** TESTS */
    public static void main(String[] args) {

        /* Demonstrating round-trip for all possible inputs. */

        for (int number = 1; number <= 3999; number++) {
            String roman = of(number);
            int parsed = parse(roman);
            if (parsed != number) {
                System.err.format(
                        "ERROR: number: %d, roman: %s, parsed: %d\n",
                        number,
                        roman,
                        parsed
                );
            }
        }

        /* Some illegal inputs. */

        int[] illegalNumbers = { -1, 0, 4000, 4001 };
        for (int illegalNumber : illegalNumbers) {
            try {
                of(illegalNumber);
                System.err.format(
                        "ERROR: Expected failure on number %d\n",
                        illegalNumber
                );
            } catch (IllegalArgumentException e) {
                // Failed as expected.
            }
        }

        String[] illegalRomans = { "MMMM", "CDCD", "IM", "T", "", "VV", "DM" };
        for (String illegalRoman : illegalRomans) {
            try {
                parse(illegalRoman);
                System.err.format(
                        "ERROR: Expected failure on roman %s\n",
                        illegalRoman
                );
            } catch (NumberFormatException e) {
                // Failed as expected.
            }
        }
    }
}
0
Halle Knast