1. 程式人生 > >羅馬數字和阿拉伯數字互化 java實現

羅馬數字和阿拉伯數字互化 java實現

首先我們來看一下羅馬數字的表數方法:
1.羅馬數字採用七個羅馬字母作數字、即Ⅰ(1)、X(10)、C(100)、M(1000)、V(5)、L(50)、D(500)
2.相同的數字連寫,所表示的數等於這些數字相加得到的數,如 Ⅲ=3;
3.小的數字在大的數字的右邊,所表示的數等於這些數字相加得到的數,如 Ⅷ=8、Ⅻ=12;小的數字(限於 Ⅰ、X 和 C)在大的數字的左邊,所表示的數等於大數減小數得到的數,如 Ⅳ=4、Ⅸ=9;
4.正常使用時、連寫的數字重複不得超過三次;
5.在一個數的上面畫一條橫線、表示這個數擴大 1000 倍。

注意以下幾個規則:
1.基本數字 Ⅰ、X 、C 中的任何一個、自身連用構成數目、或者放在大數的右邊連用構成數目、都不能超過三個;放在大數的左邊只能用一個;
2.不能把基本數字 V 、L 、D 中的任何一個作為小數放在大數的左邊採用相減的方法構成數目;放在大數的右邊採用相加的方式構成數目、只能使用一個;
3.I只能用在V和X左邊;X只能用在L和C左邊;C只能用在D和M左邊。

首先我們可以想一想這樣的計數體系的特點是什麼。因為不能輸出上劃線所以討論過大的數沒有意義,那麼不用上劃線所能表示的最大的數是多少呢?沒錯你應該已經想到了MMMCMXCIX——3999。這種計數體系的倍數關係並不明顯,而加數關係更加明顯。比如369,先表示300——CCC,然後60——LX,然後9——IX。連起來就是CCCLXIX。……

 public static String ArabToRoman(int Arab){
     String Roman = "";
     String[][] list={
                {"","I","II","III","IV"
,"V","VI","VII","VIII","IX"}, {"","X","XX","XXX","XL","L","LX","LXX","LXXX","XC"}, {"","C","CC","CCC","CD","D","DC","DCC","DCCC","CM"}, {"","M","MM","MMM","","","","","",""} }; Roman += list[3][Arab/1000%10]; Roman += list[2][Arab/100%10]; Roman += list[1][Arab/10
%10]; Roman += list[0][Arab%10]; return Roman; }

阿拉伯數字轉羅馬數字主要就是按10進位制位數決定每位字元就可以了。從羅馬數字轉阿拉伯數字就稍微繁瑣一些,因為每個10進位制位對應的字串長度是不定的。我首先想到的是按位判斷,每次判一個字元,然後加上相應的值,粗苯一些但是能工作:

public static int RomanToInt(String roman)
    int res=0;
    try {
        while(roman.charAt(0)=='M'){res+=1000;roman = roman.substring(1);}
        if(roman.charAt(0)=='D'){res+=500;roman = roman.substring(1);}
        while(roman.charAt(0)=='C'){res+=100;roman = roman.substring(1);}
        if(roman.charAt(0)=='D') {res+=300;roman = roman.substring(1);}
        else if(roman.charAt(0)=='M'){res+=800; roman = roman.substring(1);}
        if(roman.charAt(0)=='L'){res+=50;roman = roman.substring(1);}
        while(roman.charAt(0)=='X'){res+=10;roman=roman.substring(1);}
        if(roman.charAt(0)=='L'){res+=30;roman=roman.substring(1);}
        else if(roman.charAt(0)=='C'){res+=80;roman=roman.substring(1);}
        if(roman.charAt(0)=='V'){res+=5;roman=roman.substring(1);}
        while(roman.charAt(0)=='I'){res+=1;roman=roman.substring(1);}
        if(roman.charAt(0)=='V'){res+=3;roman=roman.substring(1);}
        else if(roman.charAt(0)=='X'){res+=8;roman= roman.substring(1);}
    } catch (StringIndexOutOfBoundsException e) {
            return res;
    }
    return res;
}

當字串被擷取成為了一個空串之後,再呼叫charAt(0)就會報錯了,這個時候我們把它捕獲,適時地返回已經得到的整數。
還有另外一個用到鍵值對和正則表示式的方法,馬住下次再更。

———————————二更——————————

public static int RomanToInt3(String Roman){
    int res = 0;
    String regex=null;
    String s = "'',0,I,1,II,2,III,3,IV,4,V,5,VI,6,VII,7,VIII,8,IX,9,X,10,XX,20,XXX,30,XL,40,L,50,LX,60,LXX,70,LXXX,80,XC,90,C,100,CC,200,CCC,300,CD,400,D,500,DC,600,DCC,700,DCCC,800,CM,900,M,1000,MM,2000,MMM,3000";
    String c[]=s.split(",");//將字串打散,存入陣列s
    Pattern p;//正則
        //遍歷迴圈,正則匹配
    for(int t=c.length-2;t>0;t-=2){
        String roma = c[t];
        int value = Integer.parseInt(c[t+1]);
        regex="^("+roma+")";      p=Pattern.compile(regex,Pattern.CASE_INSENSITIVE);
        Matcher matcher=p.matcher(Roman);
        if(matcher.find()){
            res += value;
           Roman=Roman.substring(((String)roma).length());
//              System.out.print(Roman + "\t\t");
//              System.out.print(regex + "\t\t");
//              System.out.println(res);
        }
    }
    return res;
}

本來想用Map儲存鍵值對,但是遍歷Map中的元素用到的Iterator不是根據放入的鍵值對先後順序進行遍歷的,而是根據字母表順序。也就是每次遍歷時先找C,再找CC……這就很尷尬,因為CM的話是表示900,而Iterator會先找到C,再找到M,就變成了1100。所以我就直接用了一個字串陣列,從大到小遍歷,這樣從高位到地位是不會產生羅馬數字歧義的。正則表示式確實是字串處理的利器。