コラム / バイナリエディタ / 23



テキストにバッファを入れる部分を作りましょう。
       //バイトを抜き出す
       while Length(str)>0 do begin
           byteStr:=Copy(str,1,2);
           Delete(str,1,2);

           //テキストをバッファに入れる
           byteStr:='0x'+byteStr;
           try
               buf:=StrToInt(byteStr);
           except
               on EConvertError do begin
                   showmessage('(´・ω・`)変なの入ってるぽ・・・');
                   FS.Free;
                   Exit;
               end;
           end;

           //ファイルにバッファを書き込む
       end;
さぁさぁ 一気に増えました。増えた部分をピックアップ
           //テキストをバッファに入れる
           byteStr:='0x'+byteStr;
           try
               buf:=StrToInt(byteStr);
           except
               on EConvertError do begin
                   showmessage('(´・ω・`)変なの入ってるぽ・・・');
                   FS.Free;
                   Exit;
               end;
           end;
一行目は、さっき切り出した2文字に 0x をつけてます。
a:='0x'+a;
で、aの前に0xが入るのは、まぁ説明しなくてもわかると思います。
a:=a+'尻尾'; なら、aの後ろに入るわけで
おにゃのこ:='猫耳'+おにゃのこ+'尻尾';
ってやれば完璧 ハァハァ
世の中的? に、16進数で書いた数字は、頭に、0x(ゼロエックス
をつけるらしくて、
StrToIntという関数も、0xが付いてると16進数として認識します。
まぁそれは今せつめいしまっすよ
try - except - end; 構文 が出てきました。
自分としては、構文の中で一番難しい奴です。
try
    処理
except
    例外発生時処理
end;
というように使います。
try-except-end;構文に入ると、
まずは、try - except に書いてある処理が普通に実行されます。
普通にしていればそのあと end の下に行きます。
ところが、もし、try-exceptでエラーが発生すると、
残りの処理は無視して except-end; に行きます。
except-end; では、エラーを扱うオブジェクト、
「例外オブジェクト」 とかいう怪しい奴に基づいて分岐できます。
その時は、
on 例外オブジェクトの型 do begin
    その例外が発生した時の処理
end;
という風に分岐します。
今回のソースを追ってみましょう。
           try
               buf:=StrToInt(byteStr);
           except
               on EConvertError do begin
                   showmessage('(´・ω・`)変なの入ってるぽ・・・');
                   FS.Free;
                   Exit;
               end;
           end;
まず、try-exceptが実行されるわけです。
buf:=StrToInt(byteStr);
ですね。
StrToIntは、与えられた「数字の文字列」を数値 にして返します。
数字の文字列 っていうのは、
「0,1,2,3,4,5,6,7,8,9」の文字でできた文字列 ってことです。
StrToIntは、文字列の頭が、
「0x」だと、16進数の文字列として読み取り、
「0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,A,B,C,D,E,F」
に対応する・・・
ここまで書いて気付いた。IntToStrを使えばいいのに、
さっきまでHexToBinを使う気だったので、混乱してましたが、
IntToStrの場合、小文字に変換する処理が必要ないですwww
後で直します。
さて、
buf:=StrToInt(byteStr);
これで0xをつけた16進数テキストの入っているbyteStrを変換して、
byte型のbufに入れるわけです。
で、try-exceptを使ってるんだから、エラー、いや 例外オブジェクトが
発生する可能性があるわけです。
なぜか。
StrToIntは、解析できない文字が出てくると、
EConvertError 型の例外を発生するのです。
もし発生した場合、
bufに代入される前に右辺が計算されているので、
StrToIntから即座にexcept-endに飛びます。
あと絶体絶命危機一髪のところで、「buf:=」はシカトされます。
でわ、except-endを見て見ましょう。
               on EConvertError do begin
                   showmessage('(´・ω・`)変なの入ってるぽ・・・');
                   FS.Free;
                   Exit;
               end;
ですね。
on 例外オブジェクトの型 do begin
    その例外が発生した時の処理
end;
ですから、
この場合、
EConvertErrorが発生していたら、begin-endを通ります。
では、begin-endを注目
                   showmessage('(´・ω・`)変なの入ってるぽ・・・');
                   FS.Free;
                   Exit;
showmessageは文字列を引数にダイアログを出す命令でしたね。
手軽なので自分は良く使います。
一個飛ばして、一番最後にExit;
困ったから手続きを強制終了しちゃうわけですね。
このExitの前にFS.free;があるのはカナリ重要です。
もし、これを書かないでExit;しちゃった場合、
「ファイルを開きっぱなしのまま」になります。
しかも、次、この手続きに来たときは、
FS:=TFileStream.Create(略);
でFSの枠に、新しいTFileStreamのインスタンスがはめられちゃうわけですから、
古いファイルストリームは永遠に制御できなくなる
という恐怖の自体が発生します。
アプリケーションが終了するまでメモリを食い続けるファイルストリーム・・・
ざわ・・・ざわざわ・・・・・・ざわ・・・・・
というわけで、手続きを強制終了したりするようなコードを書くときは、
そこまでに生成したインスタンスを解放するのは
ビルゲイツとのお約束ですよ
まぁまとめると、
「バイナリ1バイト分を表すテキストを、
 実際に数値に変換し、bufに代入するが、
 もし変換できなかったら、
 「(´・ω・`)ダイアログ」を出した後、
 使うつもりだったファイルストリームを解放し、
 強制終了する」
っていう分です。 うわ 複雑!むず!
ま、そんな感じ。
さて、小文字に変換するコードが要らなかったので、削除しましょう。
       //大文字を小文字にする
       str:=LowerCase(str);
 
に。
ここでいったん確認してみますか。
procedure SaveBinText(SaveTo:String);
var
    line:Integer;
    buf:Byte;
    str:String;
    hsp:Integer;
    byteStr:String;
begin
    FS:=TFileStream.Create(SaveTo,fmCreate);

    //ここに処理
    for line:=0 to Form1.Memo1.Lines.Count-1 do begin
        //一行あたりの処理
        str:=Form1.Memo1.Lines[line];

        //半角スペースを抜く
        while True do begin
            hsp:=pos(' ',str);
            if hsp=0 then break;
            Delete(str,hsp,1);
        end; 

        //バイトを抜き出す
        while Length(str)>0 do begin
            byteStr:=Copy(str,1,2);
            Delete(str,1,2);

            //テキストをバッファに入れる
            byteStr:='0x'+byteStr;
            try
                buf:=StrToInt(byteStr);
            except
                on EConvertError do begin
                    showmessage('(´・ω・`)変なの入ってるぽ・・・');
                    FS.Free;
                    Exit;
                end;
            end;

            //ファイルにバッファを書き込む
        end; 

    end;

    FS.Free;
end;
もうこんなになってます。
ちょっとずつ作ると、長いプログラムでもなんてことないですよね。
まぁ、あとちょこっとですが 先走ってみた。
またあとで。