Guile基礎/テキストファイルの入出力(ライブラリ)

変更履歴

概 要

目 次

参考資料

end-of-file オブジェクト

以下に示す入力用手続きは,ファイルの終端(end of file)に到達したら end-of-file オブジェクト を返します.入力用手続きの返り値が end-of-file オブジェクトか否かを判定するためには次の手続きを使用します.この手続きはコアモジュールで定義されています.

procedure:
(eof-object? obj)
obj 任意のオブジェクト
返り値 ブール値
備考 コアモジュール

この手続きは,obj が end-of-file オブジェクトのとき #t を返し, そうでないとき #f を返します.

モジュールのロード

以下に説明する手続きを利用するためには,(ice-9 textual-ports) モジュールをロードしなければなりません.
(use-modules (ice-9 textual-ports))

文字単位の入出力

procedure:
(get-char port)
port 入力ポート
返り値 文字または end-of-file オブジェクト

この手続きは,portから1文字を取得し, ファイルポインタを1文字分進めたあと,取得した文字を返します. ただし,ファイルの終端に到達していたときには end-of-file オブジェクトを返します.

具体例

以下のプログラムは,コマンドライン引数からファイル名(filename)を取得して, そのファイルから1文字ずつ読み込んで,各文字にスラッシュ(/)を付けて表示します.
;; input-chars.scm

(use-modules (ice-9 textual-ports))

(let ((filename (cadr (command-line))))
  (call-with-input-file filename 
    (lambda (port)
      (let loop ((ch (get-char port)))
        (unless (eof-object? ch) 
          (format #t "~A/" ch)
          (loop (get-char port))))
      (newline))))
以下では適当なテキストファイルに対して実行しています. 表示結果の最後にスラッシュだけが表示されています. これはテキストファイルの行末にある改行文字にスラッシュを付けて表示しているためです.改行文字は1行目の最後(o/の直後)に表示されています(見えませんけど). つまり,get-char 手続きは改行文字も1つの文字として読み込みます.
$ cat data.txt
あaいiうuえeおo
$ guile -s input-chars.scm data.txt
あ/a/い/i/う/u/え/e/お/o/
/

procedure:
(lookahead-char port)
port 入力ポート
返り値 文字または end-of-file オブジェクト

この手続きは,portから1文字を取得し,取得した文字を返します. ファイルポインタは同じ文字のところに留まって先に進みません. ファイルの終端に到達していたときには end-of-file オブジェクトを返します.

具体例

以下のプログラムは,テキストファイル(filename)から lookahead-char を使って1文字を読み込み,それと同じ文字を get-char を使ってもう一度読み込んで,それら2つの文字を星印(*)で繋いだものにスラッシュを付けて表示しています.
;; input-chars.scm

(use-modules (ice-9 textual-ports))

(let ((filename (cadr (command-line))))
  (call-with-input-file filename 
    (lambda (port)
      (let loop ((ch (lookahead-char port)))
        (unless (eof-object? ch) 
          (format #t "~A*~A/" ch (get-char port))
          (loop (lookahead-char port))))
      (newline))))
最後の2行は改行文字を2文字分表示していることによります.1行目の最後(o*o/の直後)に lookahead-char で読み込んだ改行文字を表示し(そのため改行し),星印(*)を表示したあと get-char で読み込んだ改行文字を表示し(そのため改行し),最後にスラッシュを表示しています.
$ cat data.txt
あaいiうuえeおo
$ guile -s input-chars.scm data.txt
あ*あ/a*a/い*い/i*i/う*う/u*u/え*え/e*e/お*お/o*o/
*
/

procedure:
(unget-char port char)
port 入力ポート
char 文字
返り値 char

この手続きは, 文字(char)を入力ポート(port)に押し戻します. 実際には,入力ポート(port)が使用しているバッファに保存し直します. 筆者が調査した限りでは,必要に応じてバッファを拡張するようなので, 何文字でも押し戻せると思います.押し戻した文字に対して get-char などを使って取り出したとき,押し戻した順とは逆順(いわゆる,last-in first-out の順)に取り出すことになります.返り値は第2引数に指定した文字(char)そのものです.

注意

標準入力に対してはうまく機能しません.バッファを持っていないためです(参照:Guile[6.12.9 Default Ports for Input, Output and Errors]).

procedure:
(put-char port char)
port 出力ポート
char 文字
返り値 unspecified

この手続きは, 文字(char)を出力ポート(port)に出力します.

具体例

以下のプログラムは,カレント出力ポート(標準出力)に, 文字コード(UTF-8)で #x3042〜 #x304f の文字を出力します. なお,#x3042 は「あ」の文字コード(UTF-8)です.
;; output-chars.scm
(use-modules (ice-9 textual-ports))
(let loop ((ch #x3042))
  (when (< ch #x3050)
    (put-char (current-output-port) (integer->char ch))
    (loop (1+ ch))))
(newline)
$ guile -s output-chars.scm
      ...... コンパイルメッセージ ......
あぃいぅうぇえぉおかがきぎく

文字列単位の入出力

procedure:
(get-string-n port count)
port 入力ポート
count 非負整数値(文字数)
返り値 文字列または end-of-file オブジェクト

この手続きは,入力ポート(port)から count で指定された文字数分の文字を読み込んで,それらの文字からなる文字列を返します. テキストファイルの終端に到達するまえに1文字以上は残っているけれども count 数分の文字がない場合,残っている文字すべてからなる文字列を返します.1文字もないときには end-of-file オブジェクトを返します. 文字を読み込んだときには,読み込んだ文字数分だけファイルポインタを進めます. 以下に簡単な実行例を示します.
$ cat data.txt
あaいiうuえeおo
$ guile
GNU Guile 3.0.5
      ...... 起動メッセージ ......
guile> (use-modules (ice-9 textual-ports))
guile> (define port (open-input-file "data.txt"))
guile> (get-string-n port 5)
$1 = "あaいiう"
guile> (close-port port)
$2 = #t

procedure:
(get-string-all port)
port 入力ポート
返り値 文字列または end-of-file オブジェクト

この手続きは,入力ポート(port)からすべての文字を読み込んで, それらの文字からなる文字列を返します.1文字もないときには end-of-file オブジェクトを返します.以下に簡単な実行例を示します.
$ cat data.txt
あaいiうuえeおo
kaかkiきkuくkeけkoこ
$ guile
GNU Guile 3.0.5
      ...... 起動メッセージ ......
guile> (use-modules (ice-9 textual-ports))
guile> (define port (open-input-file "data.txt"))
guile> (get-string-all port)
$1 = "あaいiうuえeおo\nkaかkiきkuくkeけkoこ\n"
guile> (close-port port)
$2 = #t

注意

上の実行例を見ると分かるように, 各行の行末にある改行文字(\n)も返り値の一部になっています. これは,後述する行単位の入力と対照的です.

procedure:
(get-string-n! port string start count)
port 入力ポート
string 文字列オブジェクト
start 非負整数値(文字位置)
count 非負整数値(文字数)
返り値 整数(文字数)または end-of-file オブジェクト

この手続きは,countで指定された文字数分の文字を入力ポート(port)から読み込んで,それらの文字からなる文字列を文字列オブジェクト(string)のstartから始まる位置に格納します.また,ファイルポインタを読み込んだ文字数だけ進めます.

テキストファイルに残っている文字数が count 以上のときには, 上の通りの処理を行って count を返り値として返します. 残っっている文字数が count より小さいときには,残っている文字をすべて読み込んで上で述べたように string に格納して,読み込んだ文字数を返します.1文字も残っていないときには end-of-file オブジェクトを返します.

注意

具体例

$ cat data.txt
あaいiうuえeおo
$ guile
GNU Guile 3.0.5
      ...... 起動メッセージ ......
guile> (use-modules (ice-9 textual-ports))
guile> (define port (open-input-file "data.txt"))
guile> (define str (make-string 10 #\x))
guile> str
$1 = "xxxxxxxxxx"
guile> (get-string-n! port str 4 5)
$2 = 5
guile> str
$3 = "xxxxあaいiうx"
文字列定数に対しては変更できません.以下はそのような実行例です.
guile> (define strc "0123456789")
guile> strc
$4 = "0123456789"
guile> (get-string-n! port strc 4 5)
string is read-only: "0123456789"

procedure:
(unget-string port string)
port 入力ポート
string 文字列オブジェクト
返り値 string

この手続きは,文字列(string)を入力ポート(のバッファ)に押し戻します.そのあとで入力ポートから入力すると押し戻した文字列の先頭から読み込まれます. 複数の文字列を押し戻した場合,文字列自体は押し戻した順とは逆順に読み込まれます. 返り値は,押し戻した文字列そのものです.以下に簡単な実行例を示します.
$ cat data.txt 
あaいiうuえeおo
kaかkiきkuくkeけkoこ
$ guile
GNU Guile 3.0.5
      ...... 起動メッセージ ......
guile> (use-modules (ice-9 textual-ports))
guile> (define port (open-input-file "data.txt"))
guile> (unget-string port "ガイル")
$1 = "ガイル"
guile> (get-char port)
$2 = #\ガ
guile> (get-line port)
$3 = "イルあaいiうuえeおo"
guile> (unget-string port "Guile Scheme\n")
$4 = "Guile Scheme\n"
guile> (get-line port)
$5 = "Guile Scheme"
guile> (close-port port)
$6 = #t

procedure:
(put-string port string)
(put-string port string start)
(put-string port string start count)
port 出力ポート
string 文字列オブジェクト
start 非負整数値(文字位置).省略時は0が設定されます.
count 非負整数値(文字数).省略時は,「文字列(string)の長さ $-$ start」(つまり,start以降末尾までの長さ)が設定されます.
返り値 unspecified

この手続きは,文字列(string)を出力ポート(port)に出力します.start が指定されたときには start 以降末尾までの部分文字列を出力します.さらに,count が指定されたときには start 以降の count 分の文字を出力します. 以下に簡単な実行例を示します.
guile> (use-modules (ice-9 textual-ports))
guile> (define str "0123456789")
guile> (put-string (current-output-port) str) (newline)
0123456789
guile> (put-string (current-output-port) str 3) (newline)
3456789
guile> (put-string (current-output-port) str 3 5) (newline)
34567

行単位の入出力

procedure:
(get-line port)
port 入力ポート
返り値 文字列または end-of-file オブジェクト

この手続きは,入力ポート(port)から1行分の文字列を読み込んで返します.さらに,ファイルポインタを次の行の先頭に進めます. ファイルの終端に到達していたら end-of-file オブジェクトを返します.

注意

具体例

$ cat data.txt 
あaいiうuえeおo
kaかkiきkuくkeけkoこ
$ guile
GNU Guile 3.0.5
      ...... 起動メッセージ ...... 
guile> (use-modules (ice-9 textual-ports))
guile> (define port (open-input-file "data.txt"))
guile> (get-line port)
$1 = "あaいiうuえeおo"
guile> (get-line port)
$2 = "kaかkiきkuくkeけkoこ"
guile> (get-line port)
$3 = #<eof>
guile> (close-port port)
$4 = #t

ファイルポインタの位置情報の取得と設定

procedure:
(port-line port)
(port-column port)
port ポート
返り値 整数値(行番号または列番号)

これらの手続きは,ファイルポインタが位置する行番号や列番号を返します. なお,行番号も列番号もともに 0 から始まります.

具体例

以下は,2行からなるファイル(data.txt)に対して,第0行を get-line を使って読み飛ばし,続けて第1行の先頭から5文字を get-string-n を使って読み飛ばした状態で,port-line と port-column を実行しています.
$ cat data.txt
あaいiうuえeおo
kaかkiきkuくkeけkoこ
$ guile
GNU Guile 3.0.5
      ...... 起動メッセージ ......
guile> (use-modules (ice-9 textual-ports))
guile> (define port (open-input-file "data.txt"))
guile> (get-line port)
$1 = "あaいiうuえeおo"
guile> (get-string-n port 5)
$2 = "kaかki"
guile> (port-line port)
$3 = 1
guile> (port-column port)
$4 = 5

procedure:
(set-port-line! port line)
(set-port-column! port column)
port ポート
line 行番号
column 列番号
返り値 整数値(行位置または列位置)

ポート(port)の行番号や列番号を設定します. ただ,ファイルポインタを移動するわけではないようです. 例えば,ファイルの終端に到達したあとに上の手続きを(適当に)を実行しても, ファイルポインタは終端から動きません. (何のために使用するのでしょうか?).
(おしまい)