I'm new to Java and I need to write a program that converts roman numerals to arabic numbers.
I cannot use some functions because I'm not allowed to change the begging neither the end of the given code. I need to do everything inside the the public static void main
function.
I started to search on Google and started to code. From now, I can convert only "one-letter" numerals (as X, I, V...) to arabic numbers but I cannot do this to more than elaborated numerals (XI, CCC, IX, IV...).
Can someone help me? I'm really new to Java. It's my first program language and I'm struggling to understand it.
Here is my code:
import java.util.Scanner;
class Roman {
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
int[] numbers = {1000, 500, 100, 50, 10, 5, 1 };
String symbols = "MDCLXVI";
/*******************************************
* Complete your program
*******************************************/
System.out.print("Enter a roman numeral");
final int MAX = 3999;
Scanner keyb = new Scanner(System.in);
String roman = keyb.next();
roman=roman.toUpperCase();
if(roman.matches(".*[0-9].*") || !roman.matches("[M|D|C|L|X|V|I]*")){
System.out.println("Impossible to convert. Wrong roman numeral");
}
int i = 0; //position in the string romain
int arabic = 0; // Arabic numeral equivalent of the part of the string that
// has been converted so far
int number;
while (i < roman.length()){
char letter = roman.charAt(i); // letter at the current position in the string
if (letter == 'I'){
number = 1;
} else if (letter == 'V'){
number = 5;
} else if (letter == 'X'){
number = 10;
} else if (letter == 'L'){
number = 50;
} else if (letter == 'C'){
number = 100;
} else if (letter == 'D'){
number = 500;
} else if (letter == 'M'){
number = 1000;
} else {
number = -1;
}
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).
number = roman.charAt(i);
int nextNumber = number;
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;
}
}
System.out.println(number);
} // end while
/*******************************************
* Do not change after this line.
*******************************************/
}
}
I would suggest using an enumeration for your individual roman numerals. That makes the code nicely encapsulated.
public enum Roman {
I(1), V(5), X(10), L(50), C(100), D(500), M(1000);
private final int value;
private Roman(int value) {
this.value = value;
}
public int toInt() {
return value;
}
}
Converting a single roman numeral to an integer becomes trivial. For example:
Roman.valueOf("X").toInt();
The only complex bit is coping with "IX" and "XC" type of values. The easy way to identify these is that they are the only time when the numerals are not in descending order of value. Checking for this can be added as methods to the enum itself (to continue encapsulation):
public enum Roman {
public boolean shouldCombine(Roman next) {
return this.value < next.value;
}
public int toInt(Roman next) {
return next.value - this.value;
}
}
Now putting it all together:
List<Roman> romans = new ArrayList<>();
input.chars().mapToObj(Character::valueOf)
.map(Roman::valueOf).forEach(romans::add);
int value = 0;
while (!romans.isEmpty()) {
Roman current = romans.remove(0);
if (!romans.isEmpty() && current.shouldCombine(romans.get(0))
value += current.toInt(romans.remove(0));
else
value += current.ToInt();
}
The first part of this code uses Java 8 features to convert the string to roman numerals. Let me know if you find that confusing and I'll convert it to traditional iteration.
Here is one way to do it:
import java.util.Scanner;
class Roman {
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
int[] numbers = { 1000, 500, 100, 50, 10, 5, 1 };
String symbols = "MDCLXVI";
/*******************************************
* Complete your program
*******************************************/
System.out.print("Enter a roman numeral: ");
final int MAX = 3999;
Scanner keyb = new Scanner(System.in);
String roman = keyb.next();
keyb.close(); // don't want a resource leak
roman = roman.toUpperCase();
if (roman.matches(".*[0-9].*") || !roman.matches("[M|D|C|L|X|V|I]*")) {
System.out.println("Impossible to convert. Wrong roman numeral");
}
int i = 0; // position in the Roman string
int current = 0; // the current Roman numeral character to Arabic
// conversion
int previous = 0; // start previous at zero, that way when
// current is greater than previous in the first
// run, nothing will be subtracted from current
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 the current position in
// the string
// switch statement is easier to read than if - else if - else
switch (letter) {
case ('I'):
current = 1;
break;
case ('V'):
current = 5;
break;
case ('X'):
current = 10;
break;
case ('L'):
current = 50;
break;
case ('C'):
current = 100;
break;
case ('D'):
current = 500;
break;
case ('M'):
current = 1000;
break;
}
if (current > previous) {
// subtract previous * 2 because previous was added to arabic
// once already
arabic += current - (previous * 2);
} else {
// if current is less than or equal to previous then add it to
// arabic
arabic += current;
}
previous = current; // set previous equal to current to check
// for less-than on next iteration
i += 1; // move on to next position in the string
} // end while
// print the Arabic conversion after the loop is done
System.out.println("Arabic: " + arabic);
/*******************************************
* Do not change after this line.
*******************************************/
}
}
In your code, the conditionals after i++
are not necessary since the while(i < roman.length())
conditional stops the loop once i >= roman.length()
.
Yet another way to do it: switch out the while
loop with a for
loop and a nested for
loop. The outer for
loop iterates over each character in the Roman numeral string. The inner for
loop iterates over each character in the symbols
string. If there is a match between the Roman numeral character and the symbols
character, then current
is set to the corresponding index in numbers
and the inner loop breaks.
for(int i = 0; i < roman.length(); i++) {
for(int s = 0; s < symbols.length(); s++) {
if(roman.charAt(i) == symbols.charAt(s)) {
current = numbers[s];
break;
}
}
if (current > previous) {
// subtract previous * 2 because previous was added to arabic
// once already
arabic += current - (previous * 2);
} else {
// if current is less than or equal to previous then add it to
// arabic
arabic += current;
}
previous = current; // set previous equal to current to check
// for less-than on next iteration
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With