練習問題

1. 行番号付きのCatコマンドの作成

例題1を改良し,行番号付きで出力する cat コマンドを作成してください. クラス名はCat2としてください. ただし,例題1と異なり,複数のファイルを指定できるようにしましょう. この例題でも,引数は必ず与えられるものとしてください.

出力例

$ cat -n Cat2.java
     1  import java.io.*;
             ...途中省略.
    23  }
$ java Cat2 Cat2.java Cat.java
     1  import java.io.*;
             ...途中省略.
    23  }
     1  import java.io.*;
             ...途中省略.
    19  }

2. Grepコマンドの作成

ここでは,grepコマンドを作成しましょう.grepコマンドとは, キーワードと1つ以上のファイル名が与えられます. ファイルの行にキーワードが含まれていれば,その行を出力するコマンドです.

クラス名はGrepとしてください. 結果出力には,以下の出力例のようにファイル名も含めてください. 複数のファイルが与えられたとしても,検索できるようにしましょう. なお,キーワードは省略されることはなく,ファイルは少なくとも1つは指定されるとして構いません.

文字列にある文字列が含まれているかを確認する

ある文字列(stringA)に,別の文字列(stringB)が含まれているかを 確認するには,containsメソッドを利用してください.

String stringA = "this is a pen";
String stringB = "is a";
String stringC = "are";
if(stringA.contains(stringB)){
  System.out.println("このメッセージは表示される.");
}
if(stringA.contains(stringC)){
  System.out.println("このメッセージは表示されない.");
}

出力例

$ grep line Cat.java
        String line;
        while((line = in.readLine()) != null){
            System.out.println(line);
$ java Grep line Cat.java
Cat.java:         String line;
Cat.java:         while((line = in.readLine()) != null){
Cat.java:             System.out.println(line);
$ java Grep class Cat.java Cat2.java
Cat.java: public class Cat{
Cat2.java: public class Cat2{

3. Headコマンドの作成

指定された行数だけファイルの先頭から出力するコマンドheadを作成しましょう. コマンドライン引数では,行数とファイル名を受け取ってください. ただし,ファイル名は省略可能です.ファイル名が省略された場合,標準入力から読み込むようにしてください. クラス名は Headとしてください.

コマンドライン引数が1つしか与えられなかった時に,標準入力(System.in)から受け取るようにするには, 次のようなコードで BufferedReaderを構築してください. 標準入力,標準出力については,基礎プログラミング演習IIの講義資料を確認してください.

BufferedReader in;
// コマンドライン引数が1つしか与えられなかった場合.
if(args.length == 1){
  in = new BufferedReader(new InputStreamReader(System.in));
}
else{
  in = new BufferedReader(new FileReader(args[1]));
}

出力例

$ head -3 Cat.java     # Cat.java の先頭3行を出力する.
import java.io.*;

public class Cat{
$ java Head 3 Cat.java # Cat.java の先頭3行を出力する.
import java.io.*;

public class Cat{
$ cat Cat.java | java Head 4 # 入力を標準入力から受け取る
import java.io.*;

public class Cat{
    void run(String[] args) throws IOException{

cat Cat.java | java Head 4 とコマンドを実行した時に,標準入力から入力を受け取ることになります. そうでない場合(ファイルをコマンドライン引数で指定した場合)は, java Head 3 Cat.java のようなコマンドの入力になります.

4. Teeコマンドの作成

ここでは,teeコマンドを作成しましょう.teeコマンドは 標準入力で受け取った文字列を標準出力と,指定されたファイルに出力するコマンドです. 以下の図のように T の形に入力を分配するところから名付けられています.クラス名をTeeとしてください.

tee

コマンドライン引数にファイル名を受け取ってください. また,標準入力から値を受け取るようにしましょう.上記のようにBufferedReaderを 構築した後は,Catの時と同じように入力を受け取れば良いです. 入力が終わればnullが返ってきますので,自動的にループを抜けるようになっています.

出力例

$ cat hoge # hoge というファイルがないことを確認する.
cat: hoge: No such file or directory
$ cat Cat.java | java Tee hoge # 標準出力と hoge に出力する.
import java.io.*;
    ...途中省略
}
$ cat hoge # hoge の内容を確認する.
import java.io.*;
    ...途中省略
}

5. カエサル暗号

カエサル暗号(Caesar暗号; シーザー暗号)はアルファベットを$n$文字ずらす暗号化方式です. この$n (0 \leq n \leq 256)$が鍵となります.

例えば,$n=1$の時,"abracadabra" という文字列はそれぞれ1文字ずれて 'bcsbdbebcsb' になります ('a''b''b''c''r''s',...のようにずらしていきます).

クラス名は CaesarCipherとし,コマンドラインで3つの引数を受け取ってください. 引数は最初から鍵,入力ファイル,出力ファイルとしてください.

ヒント

文字データを扱うように見えますが,Reader/Writer を使うより,InputStream/OutputStream を使う方が良いでしょう.

InputStream/OutputStreamを利用する場合,文字は単なる数値として扱われますので,1バイト読み込み,暗号化処理を行い,1バイト書き出してください. 暗号化処理は単純に読み込んだデータに鍵を足せば良いです. ただし,暗号化の計算結果が 0以上,256未満になるようにしてください. 暗号化の計算結果が負数であった場合は256を足し,256以上であれば,計算結果から256を減算してください (計算した結果の値が1バイトに収まっている必要があります).

出力例

$ java CaesarCipher 10 CaesarCipher.java encrypted # 鍵を10にして暗号化する.
$ cat encrypted
swzy|~*tk?k8sy84Ezlvsm*mvk}}*Mko}k|Mszro|?***# ..... 以降省略
$ java CaesarCipher -10 encrypted plain # 復号(暗号文を元の文に戻す)する.
$ diff CaesarCipher.java plain # 全く同じはずなので,何も出力されない.
$