[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [表紙] | [目次] | [索引] | [検索] [上端 / 下端] [?] |
表示(printing)とは Lispオブジェクトをテキスト表現へ変換する操作であり、 読み取り(reading)は逆の変換操作です。 これには、2. Lispのデータ型で述べた表示表現と入力構文を用います。
本章では、読み取りや表示を行うLisp関数について述べます。 また、(読み取るときに)テキストをどこから得たり、 (表示するときに)どこへ出すかを指定する ストリーム(stream)についても述べます。
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [表紙] | [目次] | [索引] | [検索] [上端 / 下端] [?] |
Lispオブジェクトの読み取りとは、 テキスト表現のLisp式を解析して対応するLispオブジェクトを生成することを 意味します。 これにより、プログラムはLispコードのファイルからLispへ取り込まれます。 テキストをオブジェクトの入力構文(read syntax)と呼びます。 たとえば、テキスト`(a . 5)'は、 CARがa
でありCDRが数5であるコンスセルの入力構文です。
Lispオブジェクトの表示とは、 オブジェクトを表現するテキストを生成することを意味します。 つまり、オブジェクトをその表示表現 (see 節 2.1 表示表現と入力構文)に変換します。 上に述べたコンスセルを表示するとテキスト`(a . 5)'を生成します。
読み取りと表示は、多かれ少なかれ、逆操作です。 与えられたテキスト断片を読み取ることで得られたオブジェクトを表示すると、 しばしば、同じテキストを生成します。 オブジェクトを表示することによって得られたテキストを読み取ると、 通常、似たようなオブジェクトを生成します。 たとえば、シンボルfoo
を表示するとテキスト`foo'を生成し、 そのテキストを読み取るとシンボルfoo
が返されます。 要素がa
とb
であるリストを表示すると テキスト`(a b)'を生成し、 そのテキストを読み取ると 要素がa
とb
である(もとと同じではないが)リストを生成します。
しかし、これら2つの操作は厳密には逆操作ではありません。 3種類の例外があります。
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [表紙] | [目次] | [索引] | [検索] [上端 / 下端] [?] |
テキストを読み取るほとんどのLisp関数は、 ストリーム(stream)を引数として受け付けます。 入力ストリームは、読み取るべきテキストの文字をどこからどのように得るのかを 指定します。 入力ストリームとして使える型は以下のとおりです。
t
t
を使うと、ミニバッファから読み取ることを意味する。 実際には、ミニバッファを表示しユーザーが指定したテキストから成る文字列を作り、 それを入力ストリームとして使う。
nil
nil
を指定すると、 standard-input
の値をかわりに使うことを意味する。 その値はデフォルト入力ストリームであり、 nil
以外の入力ストリームであること。
バッファであるストリームからの読み取りの例を 読み取り前後のポイント位置を含めて示します。
---------- Buffer: foo ---------- This-!- is the contents of foo. ---------- Buffer: foo ---------- (read (get-buffer "foo")) => is (read (get-buffer "foo")) => the ---------- Buffer: foo ---------- This is the-!- contents of foo. ---------- Buffer: foo ---------- |
最初の読み取りでは空白を読み飛ばしていることに注意してください。 読み取りでは、意味あるテキストのまえにある白文字はいくつでも読み飛ばします。
つぎは、マーカをストリームとして読み取る例です。 マーカの初期位置は下に示したバッファの先頭にあります。 読み取った値はシンボルThis
です。
---------- Buffer: foo ---------- This is the contents of foo. ---------- Buffer: foo ---------- (setq m (set-marker (make-marker) 1 (get-buffer "foo"))) => # |
つぎは文字列の内容から読み取ります。
(read "(When in) the course") => (When in) |
以下の例は、ミニバッファから読み取ります。 プロンプトは`Lisp expression: 'です。 (ストリームt
から読むとつねにこのプロンプトが使われる。) ユーザーの入力はプロンプトに続けて示してあります。
(read t) => 23 ---------- Buffer: Minibuffer ---------- Lisp expression: 23 RET ---------- Buffer: Minibuffer ---------- |
最後は、useless-stream
という名前の関数をストリームにした例です。 このストリームを使うまえに、 変数useless-list
を文字のリストで初期化します。 そうすると、関数useless-stream
を呼び出すたびに リスト内のつぎの文字を返すか、 リストの先頭に追加して文字を読み戻します。
(setq useless-list (append "XY()" nil)) => (88 89 40 41) (defun useless-stream (&optional unread) (if unread (setq useless-list (cons unread useless-list)) (prog1 (car useless-list) (setq useless-list (cdr useless-list))))) => useless-stream |
つぎのようにしてストリームを使って読み取ります。
(read 'useless-stream) => XY useless-list => (40 41) |
リストには開き括弧と閉じ括弧が残っていることに注意してください。 Lispリーダが開き括弧に出会うとこれで入力を終えると決定し、 それを読み戻すのです。 この時点で読み取りを試みると、 `()'を読み取ってnil
を返します。
load
で開いた入力ファイルから読み取るための 入力ストリームとして内部的に使われる。 読者はこの関数を使ってはならない。[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [表紙] | [目次] | [索引] | [検索] [上端 / 下端] [?] |
本節では読み取りに関係するLisp関数や変数について述べます。
以下の関数では、streamは入力ストリーム(前節参照)を表します。 streamがnil
であったり省略すると、 standard-input
の値をデフォルトにします。
読み取り中に閉じていないリストやベクトル、文字列に出会うと、 エラーend-of-file
を通知します。
startが指定してあると、文字列のstartで添字付け (先頭文字の添字は0)されるところから読み始める。 endを指定すると、その添字位置の直前で読み取りを終らせ、 文字列には残りの文字がないかのように扱う。
例:
(read-from-string "(setq x 55) (setq y 5)") => ((setq x 55) . 11) (read-from-string "\"A short string\"") => ("A short string" . 16) ;; 最初の文字から読み始める (read-from-string "(list 112)" 0) => ((list 112) . 10) ;; 2番目の文字から読み始める (read-from-string "(list 112)" 1) => (list . 5) ;; 7番目の文字から読み始め、9番目の文字で読み終える (read-from-string "(list 112)" 6 8) => (11 . 8) |
nil
である場合にread
が使う ストリームを保持する。[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [表紙] | [目次] | [索引] | [検索] [上端 / 下端] [?] |
出力ストリームは表示で生成した文字群をどのように扱うかを指定します。 ほとんどの表示関数は省略可能な引数として出力ストリームを受け付けます。 出力ストリームとして使える型は以下のとおりです。
t
nil
nil
を指定すると、 standard-output
の値をかわりに使うことを意味する。 その値はデフォルト出力ストリームであり、 nil
以外であること。
正当な出力ストリームの多くは、入力ストリームとしても正当です。 入力ストリームと出力ストリームの違いは、 オブジェクト型の違いというよりは、 読者がLispオブジェクトをどのように使うかです。
バッファを出力ストリームとして使った例を示します。 ポイントの初期位置は以下に示すように`the'の`h'の直前にあります。 終了後でも、ポイントは同じ`h'の直前に位置しています。
---------- Buffer: foo ---------- This is t-!-he contents of foo. ---------- Buffer: foo ---------- (print "This is the output" (get-buffer "foo")) => "This is the output" ---------- Buffer: foo ---------- This is t "This is the output" -!-he contents of foo. ---------- Buffer: foo ---------- |
つぎは、マーカを出力ストリームとして用いた例です。 バッファfoo
のマーカの初期位置は、 単語`the'の`t'と`h'のあいだにあります。 終了後には、マーカは挿入したテキストを越えて同じ`h'の直前に位置します。 ポイント位置はなんの影響もないことに注意してください。
---------- Buffer: foo ---------- This is the -!-output ---------- Buffer: foo ---------- (setq m (copy-marker 10)) => # |
つぎは、エコー領域への出力の例です。
(print "Echo Area output" t) => "Echo Area output" ---------- Echo Area ---------- "Echo Area output" ---------- Echo Area ---------- |
最後は、関数を出力ストリームとして使った例を示します。 関数eat-output
は与えられた文字を受け取り、 それをリストlast-output
の先頭にコンスします (see 節 5.5 コンスセルとリストの構築)。 終了後には、リストがすべての出力文字を保持していますが逆順です。
(setq last-output nil) => nil (defun eat-output (c) (setq last-output (cons c last-output))) => eat-output (print "This is the output" 'eat-output) => "This is the output" last-output => (10 34 111 32 101 104 116 32 115 105 32 115 105 104 84 34 10) |
リストの順番を逆にすれば正しい順序の出力になります。
(concat (nreverse last-output)) => " \"This is the output\" " |
concat
を呼び出してリストを文字列に変換し、 内容を読みやすいようにしました。
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [表紙] | [目次] | [索引] | [検索] [上端 / 下端] [?] |
本節ではLispオブジェクトを表示する、 つまり、オブジェクトを表示表現に変換するLisp関数について述べます。
Emacsの表示関数のなかには、正しく読み取れるように クォート文字を出力に追加するものがあります。 使用されるクォート文字は`"'と`\'です。 これらは、文字列とシンボルを区別したり、 文字列やシンボル内の句読点文字を読み取るときに区切り文字として扱うこと を防ぎます。 詳しくはSee 節 2.1 表示表現と入力構文。 出力関数を選べば、クォートのありなしを指定できます。
テキストをLispシステムへ読み取る意図がある場合には、 曖昧さを避けるためにクォート文字付きで表示するべきです。 Lispプログラマに対してLispオブジェクトを明確に記述する場合も同様です。 しかし、人間向けの見やすい出力が目的であれば、 クォートせずに表示するのが普通はよいでしょう。
Lispオブジェクトはそれ自身を参照できます。 自己参照しているオブジェクトを普通の方法で表示するには 無限のテキストが必要であり、 そのような試みは無限再帰をもたらします。 Emacsはそのような再帰を検出し、 すでに表示したオブジェクトを再帰的に表示するかわりに `#level'を表示します。 たとえば、`#0'は、現在の表示操作においてレベル0のオブジェクトを 再帰的に参照することを示します。
(setq foo (list nil)) => (nil) (setcar foo foo) => (#0) |
以下の関数では、streamは出力ストリームを表します。 (出力ストリームについては前節を参照。) streamがnil
であったり省略すると、 standard-output
の値をデフォルトにします。
print
は便利な表示方法である。 オブジェクトobjectの表示表現を ストリームstreamに出力し、 objectの前後に改行を1つずつ表示する。 クォート文字を使う。 print
はobjectを返す。 たとえばつぎのとおり。
(progn (print 'The\ cat\ in) (print "the hat") (print " came back")) -| -| The\ cat\ in -| -| "the hat" -| -| " came back" -| => " came back" |
print
のようには出力を区切る改行を表示しないが、 print
と同様にクォート文字を用いる。 objectを返す。
(progn (prin1 'The\ cat\ in) (prin1 "the hat") (prin1 " came back")) -| The\ cat\ in"the hat"" came back" => " came back" |
この関数は、read
ではなく人が読みやすい出力を意図しており、 クォート文字を挿入せず、文字列を囲むダブルクォートも出力しない。 空白も追加しない。
(progn (princ 'The\ cat) (princ " in the \"hat\"")) -| The cat in the "hat" => " in the \"hat\"" |
prin1
が表示するであろう テキストから成る文字列を返す。
(prin1-to-string 'foo) => "foo" (prin1-to-string (mark-marker)) => "#" |
noescapeがnil
以外であると、 出力にはクォート文字を使わない。 (この引数は、Emacs 19版以降で使える。)
(prin1-to-string "foo") => "\"foo\"" (prin1-to-string "foo" t) => "foo" |
文字列としてのLispオブジェクトの表示表現を得るための別の方法については、 4.6 文字と文字列の変換のformat
を参照。
standard-output
を文字列への出力と設定して フォームbodyを実行する。 そして、その文字列を返す。
たとえば、カレントバッファの名前が`foo'であると
(with-output-to-string (princ "The buffer is ") (princ (buffer-name))) |
は"The buffer is foo"
を返す。
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [表紙] | [目次] | [索引] | [検索] [上端 / 下端] [?] |
nil
の場合に表示関数が用いるストリーム。nil
以外であると、 文字列内の改行文字を`\n'、ページ送り文字を`\f'と表示する。 通常、これらの文字は実際の改行やページ送りとして表示される。
この変数は、クォート付きで表示する表示関数prin1
や print
に影響を与える。 princ
には影響しない。 prin1
を用いた例を示す。
(prin1 "a\nb") -| "a -| b" => "a b" (let ((print-escape-newlines t)) (prin1 "a\nb")) -| "a\nb" => "a b" |
2番目の式では、prin1
の呼び出し中には print-escape-newlines
のローカル束縛が有効であるが、 結果を表示するときには有効ではない。
nil
以外であると、 クォート付きで表示する出力関数prin1
やprint
は、 文字列内のユニバイト非ASCII文字を無条件で バックスラッシュ列として表示する。
これらの関数は、出力ストリームがマルチバイトバッファや マルチバイトバッファのマーク位置であると、 この変数の値に関係なくユニバイト非ASCII文字に対して バックスラッシュ列を用いる。
nil
以外であると、 クォート付きで表示する表示関数prin1
やprint
は、 文字列内のマルチバイト非ASCII文字を無条件で バックスラッシュ列として表示する。
これらの関数は、出力ストリームがユニバイトバッファや ユニバイトバッファのマーク位置であると、 この変数の値に関係なくマルチバイト非ASCII文字に対して バックスラッシュ列を用いる。
値がnil
(デフォルト)であると無制限。
(setq print-length 2) => 2 (print '(1 2 3 4 5)) -| (1 2 ...) => (1 2 ...) |
nil
(デフォルト)であると無制限。[ << ] | [ >> ] | [表紙] | [目次] | [索引] | [検索] [上端 / 下端] [?] |