Aikの技術的な進捗部屋

技術的な進捗とか成果とかを細々と投稿するブログです。時々雑記も。

Javaで書く括弧検証プログラム その2

前回

括弧検証プログラムを作ろう その2

またもやチーム内課題で括弧検証プログラムを作る事になりました。
恐らく相変わらずスクリプト言語は禁止なのでしょう。うんいや気持ちは分かるけどね。

とりあえず前回と同じくJavaで挑むことにしました。
多少はJavaレベルも向上しているだろうし…どうにかなるといいな。

実装アルゴリズム

さてアルゴリズムを、と思いましたが…。
今回の課題に当たっては、アルゴリズム自体の変更はない事に気づきました。

なので、これは前回と同じという事でさっさかコード書きに行きましょう。

書きながら気づいた事

プログラムを書く時に気づいた、ちょっとした小ネタなどを記します。

括弧の英訳は数種類ある

プログラムを書いてる途中に、括弧の格納をするための変数名に悩みました。
「括弧」という言葉にも、色んな括弧がありますからね。

とりわけ今回のプログラムでは、様々な種類の括弧を扱うので…。
折角ですので各括弧の英名について調べてみました。

  • 括弧全体を表す: Bracket
    • "(", ")" -丸括弧: Parenthesis/Paren(パーレン)
    • "「", "」" -鉤括弧: Corner Bracket
    • "[", "]" -角括弧: Square Bracket
    • "{", "}" -波括弧: Brace(ブレース/ブレイス)/Curly Bracket(カーリーブラケット)/Curl(カール)
    • "<", ">" -山括弧: Angle Bracket(アングルブラケット)

参考記事(Wikipedia)
参考記事(Weblio)

広義的な「括弧」という意味では"Bracket"を使えば良さそうですね。

BufferedReaderについて

BufferedReaderについて、私は「ファイルをJava側で読み込みやすくするために色々処理した後の形なのかな」とかなり曖昧な認識をしていたため…。
これはアカンなと思い、調べてみました。

BufferedReaderとは: 文字、配列、行をバッファリングすることによって、文字型入力ストリームからテキストを効率良く読み込みます。

参照記事(Oracle公式ドキュメント)

なるほど…私の認識は的外れなものではなかったみたいです。
そういえば私が前回の括弧検証プログラムを書く際にお世話になったサイトに、

このクラスはFileReaderクラスを拡張する形で利用する~

と書かれていました。
せっかくなのでFileReaderについても調ベちゃいましょう。

FileReaderとは:
文字ファイルを読み込むための簡易クラスです。

参照記事(Oracle公式ドキュメント)

FileReaderクラスの持つ基本機能でファイルから読み込みは行うのですけど、それにBufferedReaderクラスをかぶせて使うことでまとめて読み込む機能を持てるようになります。

参照記事

な、なるほど…?分かったような分からないような…。
他にもいくつか記事を見てみましたが、どれにも「BufferedReaderはFileReaderの進化系」と言った説明が見受けられました。

また、探している中に興味深い記事がありましたので一つ。
qiita.com

こちら、タイトルにもあります様にJavaのファイル読み込み方法の読み込み速度比較をされています。
BufferedReader+FileReader以外にも、沢山の読み込み方法があるらしいですね…。

どの方法にもメリットとデメリットがあるみたいなので、目的に合った手段を選べって事ですかね。
一先ず今回のものでしたらBufferedReader+FileReaderで良さそうです。

参照型とプリミティブ型について

Javaには「プリミティブ型」と「参照型」2つのデータ型があるらしく、

  • プリミティブ型: 値を直接格納する(値を直接保持する)、先頭が小文字のもの(byte, int...)
  • 参照型: 値を直接持たず、値のある場所を参照する、型によってその大きさ(bit数)がきっちり決まっている

というようになってるらしいです。
参照型は、C言語のポインタ型みたいに考えたら良いですかね。

参考記事1
参考記事2

参考に、プリミティブ型のものを列挙しておきます。

  • boolean: 1bit/ 参照型の"Boolean"と対応
  • byte: 8bit/ 参照型の"Byte"と対応
  • char: 16bit/ 参照型の"Character"と対応
  • short: 16bit/ 参照型の"Short"と対応
  • int: 32bit/ 参照型の"Integer"と対応
  • float: 32bit/ 参照型の"Float"と対応
  • long: 64bit/ 参照型の"Long"と対応
  • double: 64bit/ 参照型の"Double"と対応

完成です!

とはいえ、前回のコードから少し変えたくらいなのですが。

相変らず超長ったらしいコードになり…。
おまけに今回は、明らかに簡略化できそうな箇所も散見されました。
ただ、明日が〆切の課題なので…とりあえずここまでにしておきます。
コーディング力を鍛えて、後日リベンジしたいです。

いつものようにソースコードを貼り付けておきます。
※長ったらしいので折りたたんでおきました

ソースコードを展開する

// 作成日 18.03.28
import java.io.File; // ファイルオブジェクト宣言用
import java.io.FileReader; // ファイルの読込屋さん
import java.io.BufferedReader; // FileReaderの強化版,FileReaderの機能を利用し更に強くなる
import java.io.FileNotFoundException; // 例外処理用
import java.io.IOException; // 例外処理用
import java.util.Deque; // スタックオブジェクト宣言用
import java.util.ArrayDeque; // Dequeの実装クラス

class checkkakko3{
    // 検査する括弧の種類を定義(アスキーコード)
    public static final char bracket1_open = 40; // "("
    public static final char bracket1_close = 41; // ")"
    public static final char bracket2_open = 60; // "<"
    public static final char bracket2_close = 62; // ">"
    public static final char bracket3_open = 91; // "["
    public static final char bracket3_close = 93; // "]"
    public static final char bracket4_open = 123; // "{"
    public static final char bracket4_close = 125; // "}"

    public static void main(String args[]){
    // 処理時間計測用タイマーセット
    long start = System.nanoTime();

    // 読み込みたいファイルのパス
    String filename = args[0];
    System.out.println("************************");
    System.out.println("Check of Brackets.");
    System.out.println("File name - " +filename);

    // ファイルの読み込み
    try{
         // 指定パスのファイルを読み込む
        File file = new File(filename);
        // ファイルが読み込めるかチェック、読みこめたら処理続行
        if (isExistReadfile(file)){
            BufferedReader br = new BufferedReader(new FileReader(file));

            String str;
            Deque<Character> bracketsStack = new ArrayDeque<Character>();

            boolean bCheck = true; // 最初に開き括弧がきた時の対処, エラー時はfalse
            // 一行ごとに文字を読み込み
            int row = 0;
            while((str = br.readLine()) != null){
                // 1文字ずつchar型に変換、配列へ
                char[] cArray = str.toCharArray();
                                           
                for (char c : cArray) {
                    if(c == bracket1_open || c == bracket2_open || c == bracket3_open || c == bracket4_open){
                        bracketsStack.addFirst(c);
                    }else if(c == bracket1_close){
                        if(bracketsStack.isEmpty()) {
                            bCheck = false;
                            break;
                        }else {
                            if(bracketsStack.getFirst() == bracket1_open){
                                bracketsStack.removeFirst();
                            }else {
                                bracketsStack.addFirst(c);
                            }
                        }
                    }else if(c == bracket2_close){
                        if(bracketsStack.isEmpty()) {
                            bCheck = false;
                            break;
                        }else {
                            if(bracketsStack.getFirst() == bracket2_open){
                                bracketsStack.removeFirst();
                            }else {
                                bracketsStack.addFirst(c);
                            }
                        }
                    }else if(c == bracket3_close){
                        if(bracketsStack.isEmpty()) {
                            bCheck = false;
                            break;
                        }else {
                            if(bracketsStack.getFirst() == bracket3_open){
                                bracketsStack.removeFirst();
                            }else {
                                bracketsStack.addFirst(c);
                            }
                        }
                    }else if(c == bracket4_close){
                        if(bracketsStack.isEmpty()) {
                            bCheck = false;
                            break;
                        }else {
                            if(bracketsStack.getFirst() == bracket4_open){
                                bracketsStack.removeFirst();
                            }else {
                                bracketsStack.addFirst(c);
                            }
                        }
                    }
                }
            }
            if(bracketsStack.isEmpty() && bCheck){
                System.out.println("");
                System.out.println("************************");
                System.out.println("Brackets Check -> Clear");
                System.out.println("************************");
            }else{
                System.out.println("");
                System.out.println("************************");
                System.out.println("Brackets Check -> failed");
                System.out.println("************************");
            }
            br.close();
        }else{ // ファイルが読みこめなかったら処理はしない
            System.out.println(filename+ "can't Read.");
        }
    }catch(FileNotFoundException e){
        System.out.println(e);
    }catch(IOException e){
        System.out.println(e);
    }

    // 処理速度計測用タイマーストップ
    long end = System.nanoTime();
    System.out.println("");
    System.out.println("Program Time:" + (end - start) / 1000000f + "ms");
    }

    /**
    * 指定したファイルが存在し、かつそれが読み込み出来るファイルかチェック
    * @param file: チェックしたいFile型のオブジェクト
    */
    private static boolean isExistReadfile(File file){
        if (file.exists()){
            if (file.isFile() && file.canRead()){
                return true;
            }
        }
        System.out.println("File is Not Found.");
        return false;
    }
}

課題が終わったとこで、やりたい事がいくつもある病気にかかり、次何やろうかな状態ですが…。

今回Eclipse使って書いたけど結構不便に感じたところもありましたし、
とりあえずEclipseカスタマイズとコードリーディングに取りかかれればと思います。

まぁそれに取り掛かる間にまたやりたいこと増えるんでしょうけれどね。