プロが教える店舗&オフィスのセキュリティ対策術

こんにちは。java初心者の学生です。
実行時引数で得た数値を漢数字に変換するコードを書いているのですがif構文の&&のところで実行時エラーが出てしまいます。
原因としては1200001234と入力した時に”args[0].length()-12が存在しない”などがあげられると思いますが、下に載せたコード以外で兆、億、万桁が0の場合の対処方がわかりません。
御享受いただけると助かります。よろしくお願いします!

public class Question14 {
/**
* 実行時引数で得た数字の漢数字変換
* @param args 数字
*/
public static void main(String[] args)
{
StringBuffer num = new StringBuffer(args[0]);
if(num.length()>20){
System.out.println("0~99999999999999999999の数値で入力してください。");
}
else{
StringBuffer sb = new StringBuffer();
if(num.equals("0")){
System.out.println("零");
}
else{
for(int keta = num.length()-1; keta>=0; keta--){
if(keta==args[0].length()-5 && !((num.substring(args[0].length()-8,args[0].length()-4).equals("0000")))){
sb.insert(0,'万');
}
else if(keta==args[0].length()-9 && !((num.substring(args[0].length()-12,args[0].length()-8).equals("0000")))){
sb.insert(0,'億');
}
else if(keta==args[0].length()-13 && !((num.substring(args[0].length()-16,args[0].length()-12).equals("0000")))){
sb.insert(0,'兆');
}
else if(keta==args[0].length()-17){
sb.insert(0,'京');
}
switch(num.charAt(keta)){
case'1':
sb.insert(0,"一");
break;
case'2':
sb.insert(0,"二");
break;
case'3':
sb.insert(0,"三");
break;
case'4':
sb.insert(0,"四");
break;
case'5':
sb.insert(0,"五");
break;
case'6':
sb.insert(0,"六");
break;
case'7':
sb.insert(0,"七");
break;
case'8':
sb.insert(0,"八");
break;
case'9':
sb.insert(0,"九");
break;
case'0':
continue;
default:
System.out.println("数値を入力してください");
break;
}
if(keta==num.length()-2||keta==num.length()-6||keta==num.length()-10||keta==num.length()-14||keta==num.length()-18){
sb.insert(1,"十");
}
else if(keta==num.length()-3||keta==num.length()-7||keta==num.length()-11||keta==num.length()-15||keta==num.length()-19){
sb.insert(1,"百");
}
else if(keta==num.length()-4||keta==num.length()-8||keta==num.length()-12||keta==num.length()-16||keta==num.length()-20){
sb.insert(1,"千");
}
}
}
System.out.println(sb);
}
}
}

A 回答 (2件)

長い条件式による if 文や、過剰に else if を多用するのは、


専門的に言うと「循環的複雑度」が高い状態となるので、
アルゴリズムを考え直す事をオススメします。

漢数字ならば
* 四桁毎の処理と一桁毎の処理の二重ループ
* あらかじめ計算できる値は、配列定数で用意
* 零の特例
* 一を省略する特例
あたりを実装すれば間違いないでしょう

// 参考例
public class KanjiNumber {
_ private static final String[] quadSuffix = "一,万,億,兆,京,垓,秭,穣,溝,澗,正,載,極,恒河沙,阿僧祇,那由他,不可思議,無量大数".split(",");
_ private static final String[] deciSuffix = "一,十,百,千".split(",");
_ private static final String[] deciChars = "零,一,二,三,四,五,六,七,八,九".split(",");
_ private List<String> buffer = new ArrayList<>();
_ private void outDeci4(int index, int num) {
_ _ if (num == 0) return;
_ _ if (index >= quadSuffix.length) throw new RuntimeException("overflow");
_ _ if (index > 0) buffer.add(quadSuffix[index]);
_ _ for (int i = 0; i < 4; i++) {
_ _ _ int n = num % 10;
_ _ _ if (i > 0 && n > 0) buffer.add(deciSuffix[i]);
_ _ _ if (i == 0 && n > 0 || n > 1) buffer.add(deciChars[n]);
_ _ _ num /= 10;
_ _ }
_ }
_ private String getFormal() {
_ _ if (buffer.size() == 0) return "零";
_ _ List<String> x = new ArrayList<>(buffer);
_ _ Collections.reverse(x);
_ _ return String.join("", x);
_ }
_ public static String parse(String arabic) {
_ _ String[] nums = arabic.replaceAll("[\\s_,]", "").replaceAll("^0+(?=\\d)", "").split("(?=(\\d{4})+$)");
_ _ KanjiNumber o = new KanjiNumber();
_ _ for (int i = 0; i < nums.length; i++) {
_ _ _ int n = Integer.parseInt(nums[nums.length - i - 1], 10);
_ _ _ o.outDeci4(i, n);
_ _ }
_ _ return o.getFormal();
_ }
_ public static void main(String[] args) {
_ _ assert KanjiNumber.parse("0").equals("零");
_ _ assert KanjiNumber.parse("1").equals("一");
_ _ assert KanjiNumber.parse("42").equals("四十二");
_ _ assert KanjiNumber.parse("1_0002").equals("一万二");
_ _ assert KanjiNumber.parse("10_0000_0900").equals("十億九百");
_ _ assert KanjiNumber.parse(String.format("30%028d", 0)).equals("三十穣");
_ _ assert KanjiNumber.parse(String.format("4000%052d", 0)).equals("四千恒河沙");
_ _ assert KanjiNumber.parse(String.format("5%068d6", 0)).equals("五十無量大数六");
_ }
}
    • good
    • 1
この回答へのお礼

Ogre7077さん、回答ありがとうございます!

参考例まで載せて頂きありがとうございます。まだjava始めたばかりなので載せて頂いたコードもよく理解出来てないですが、自分で調べてまたコード練りなおしてみます!
ありがとうございました!!

お礼日時:2014/10/31 20:27

> 原因としては1200001234と入力した時に”args[0].length()-12が存在しない”などがあげられると思います



そう思うのなら、そこを直しましょう。

! num.substring(args[0].length()-12,args[0].length()-8).equals("0000")

これが、何をしているのか、日本語で説明できますか?

args[0].length()<12 だと、 args[0].length()-12 が負になり、エラーになります。その分析は正しいです。
では、args[0].length()<12 のときに、この判定は意味があるものなのでしょうか?
    • good
    • 0
この回答へのお礼

kmeeさん、回答ありがとうございます!

まさにいまargs[0].length()<12の所で詰まっています、、、
新しく違う方法考えてみます!

お礼日時:2014/10/31 20:12

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!