| [ < ] | [ > ] | [ << ] | [ 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)を引数として受け付けます。 入力ストリームは、読み取るべきテキストの文字をどこからどのように得るのかを 指定します。 入力ストリームとして使える型は以下のとおりです。
ttを使うと、ミニバッファから読み取ることを意味する。 実際には、ミニバッファを表示しユーザーが指定したテキストから成る文字列を作り、 それを入力ストリームとして使う。
nilnilを指定すると、 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 ] | [ >> ] | [表紙] | [目次] | [索引] | [検索] [上端 / 下端] [?] |
出力ストリームは表示で生成した文字群をどのように扱うかを指定します。 ほとんどの表示関数は省略可能な引数として出力ストリームを受け付けます。 出力ストリームとして使える型は以下のとおりです。
tnilnilを指定すると、 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(デフォルト)であると無制限。| [ << ] | [ >> ] | [表紙] | [目次] | [索引] | [検索] [上端 / 下端] [?] |