Javaの大海原をじゃばじゃばと

勉強メモとか雑記です

勉強メモ@プロJava/その11

第13章 処理の難しさの段階

「プロになるJava」より gihyo.jp

13.2.1 状態遷移の管理とenum

例題

文字列が小数点付きの数値の表示として妥当かどうか判定するプログラムを考えてみましょう。

src/main/java/projava/CheckFloat.java

package projava;

public class CheckFloat {

    enum FloatState {
        START, INT, FRAC_START, FRAC, ZERO
    }

    static boolean check(String data){
        var state = FloatState.START;
        for (char ch : data.toCharArray()){
            switch (state){
                case START -> {//開始
                    if (ch == '0'){
                        state = FloatState.ZERO;
                    }else if(ch >= '1' && ch <= '9'){
                        state = FloatState.INT;
                    }else{
                        return false;
                    }
                }
                case ZERO -> {//頭のゼロ
                    if (ch == '.'){
                        state = FloatState.FRAC_START;
                    }else{
                        return false;
                    }
                }
                case INT -> {//整数部
                    if (ch >= '0' && ch <= '9'){
                        state = FloatState.INT;
                    }else if(ch == '.'){
                        state = FloatState.FRAC_START;
                    }else{
                        return false;
                    }
                }
                case FRAC_START, FRAC -> {//小数部
                    if(ch >= '0' && ch <= '9'){
                        state = FloatState.FRAC;
                    }else{
                        return false;
                    }
                }
            }
        }
        return switch (state){
            case ZERO, INT, FRAC -> true;
            default -> false;
        };
    }

    public static void main(String[] args) {
        System.out.println(check(""));
        System.out.println(check("012"));
        System.out.println(check(".12"));
        System.out.println(check("12."));
        System.out.println(check("1.2.3"));
        System.out.println(check("1..3"));
        System.out.println(check("0"));
        System.out.println(check("12"));
        System.out.println(check("12.3"));
        System.out.println(check("0.3"));
        System.out.println(check("12.30"));
    }
}

▼コンソール

おおー!!!

練習問題(上記例題の続き)

1.小数部の最後が0で終わると不適になるように判定を変更してみましょう。「12.30」や「12.0」は不適です。

2.先頭に負の符号を表すを付けることができるように判定を変更してみましょう。「123」はOKですが「123」や「123」は不適です。

src/main/java/projava/ExCheckFloat.java

package projava;

public class ExCheckFloat {

    enum FloatState {
        //「小数の末尾」「負の数」の状態を追加
        START, INT, FRAC_START, FRAC, ZERO, FRAC_END, NEGATIVE
    }

    static boolean check(String data){
        var state = FloatState.START;
        //文字カウンタを宣言
        int count = 0;
        for (char ch : data.toCharArray()){
            count++;
            switch (state){
                case START -> {//開始
                    if (ch == '0'){
                        state = FloatState.ZERO;
                    }else if(ch >= '1' && ch <= '9') {
                        state = FloatState.INT;
                    }else if (ch == '-'){
                        state = FloatState.NEGATIVE;
                    }else{
                        return false;
                    }
                }
                case NEGATIVE -> {//stateがNEGATIVE、負の数の場合
                    if (ch >= '1' && ch <= '9'){
                        state = FloatState.INT;
                    }else{
                        return false;
                    }
                }
                case ZERO -> {//頭のゼロ
                    if (ch == '.'){
                        state = FloatState.FRAC_START;
                    }else{
                        return false;
                    }
                }
                case INT -> {//整数部
                    if (ch >= '0' && ch <= '9'){
                        state = FloatState.INT;
                    }else if(ch == '.'){
                        state = FloatState.FRAC_START;
                    }else{
                        return false;
                    }
                }
                case FRAC_START, FRAC -> {//小数部
                    if (count == data.toCharArray().length){
                        if (ch >= '1' && ch <= '9'){
                            state = FloatState.FRAC_END;
                        }else {
                            return false;
                        }
                    }else{
                        if(ch >= '0' && ch <= '9'){
                            state = FloatState.FRAC;
                        }else{
                            return false;
                        }
                    }
                }
            }
        }
        return switch (state){
            case ZERO, INT, FRAC_END -> true;
            default -> false;
        };
    }

    public static void main(String[] args) {
        /*System.out.println(check(""));
        System.out.println(check("012"));
        System.out.println(check(".12"));
        System.out.println(check("12."));
        System.out.println(check("1.2.3"));
        System.out.println(check("1..3"));
        System.out.println(check("0"));
        System.out.println(check("12"));
        System.out.println(check("12.3"));
        System.out.println(check("0.3"));
        System.out.println(check("12.30"));*/
        //追加ケース
        System.out.println("練習問題1のチェック");
        System.out.print("12.30はfalseでしょ?:");
        System.out.println(check("12.30"));
        System.out.print("12.0はfalseでしょ?:");
        System.out.println(check("12.0"));
        System.out.print("0.0はfalseでしょ?:");
        System.out.println(check("0.0"));
        System.out.println("");
        System.out.println("練習問題2のチェック");
        System.out.print("-123はtrueでしょ?:");
        System.out.println(check("-123"));
        System.out.print("--123はfalseでしょ?:");
        System.out.println(check("--123"));
        System.out.print("-12-3はfalseでしょ?:");
        System.out.println(check("-12-3"));
        System.out.print("-1.0はfalseでしょ?:");
        System.out.println(check("-1.0"));
    }
}

▼コンソール

ひとまずいけたと思われる!
しかーし、stateがFRAC_STARTまたはFRACの時のifネストが深すぎ??うーむ。

答え合わせ!

nowokay.hatenablog.com

練習問題1について。
その時アクティブな要素がゼロならステータスをFRAC_STARTにすればよかったのか!!
そしたらカウンタ用意する必要もなかったのだ〜〜なるほど!!

練習問題2について。
「−」符号の後ろに「0」がくるのはNGという前提で書いたけど、その場合はステータスをZEROにすれば良いのか。
うおおおお。ちょっと待って混乱してきた。あかん…明日解説ブログ読み直す😂