Menu

Rの出力と入力(print・cat・readline)

Rの出力の仕組み(自動表示、print()とcat()の違い、message())と、readline()やreadLines()でユーザー入力を読み取る方法を解説します。

このページのコードはエディタで実行できます - 編集してすぐに結果を確認できます。

Rの表示の仕組み

Rには他の主要言語にはない癖があります。コンソールでは、print文がまったく不要なのです。変数名を入力してEnterを押せば、Rがその値を表示します。これが自動表示で、Rのチュートリアルが裸の式であふれている理由です。

しかし自動表示には厳密な境界があります。発動するのはトップレベルの式に対してだけです。for ループや関数本体の内側では、裸の値は評価された後、静かに捨てられます。

単独の x は表示され(トップレベルなので)、最初のループは何も表示せず、2つ目のループは明示的に頼んでいるので 123 を表示します。「ループは動くのに何も出ない」はRで最も多く尋ねられる質問のひとつで、答えはこれがすべてです。ループや関数の内側では、表示は常にあなたの仕事です。(Rscriptでスクリプトを実行するときも同じです。コンソールで1行ずつ動かしていたときは表示されたものが、ループの中では黙り込むことがあります。)

print():形式に忠実なほう

print() はRが見ているとおりに値を表示します。だからこそデータを調べるには適した道具であり、洗練された出力を作るには不向きな道具です。

目を引く点が2つあります。文字列は引用符を保ちます。print() は忠実な表現を見せており、引用符はそれが文字列の値であることを教えてくれます。そして各行は [1] のような角かっこ付きの数字で始まります。これはその行の最初の要素の添字で、長いベクトルが折り返されるとき、その行がどの要素から再開するかを示してくれます。ノイズではなく、ベクトルを読むための補助です。

引用符なしで print() 風の出力が欲しいなら、print(x, quote = FALSE) でも noquote(x) でも実現できます。ただしその時点で本当に欲しいのは、たいてい cat() です。

cat():人のための出力

cat()(concatenate-and-print)は生のテキストを書き出します。引用符も添字の接頭辞もなく、引数はスペースでつながれます。その制御と引き換えに、何も自動では足されません。改行も含めてです。

"\n" を忘れるのは cat() の通過儀礼のようなもので、これがないと次の出力が同じ行にくっつきます。cat() の呼び出しは "\n" で終える、と反射的にできるようにしましょう。

2つの関数の引用符の違いは、実のところ何を見せているかの違いです。print() はエスケープシーケンスを入力したとおりに表示し、cat() はそれを描画します。

print() は引用符の中に \t\n をそのまま見せます。文字列が正確に何を含んでいるかをデバッグするときに便利です。cat() はそれを本物のタブと本物の改行に変えます。出力を作るときに便利です。意図で選びましょう。調べるなら print()、見せるなら cat()。

書式付きレポート:sprintf() + cat()

cat() のスペース区切りの引数でできることには限界があります。桁を揃えた書式付きの出力——小数点以下を固定する、カウンタを詰め物で揃える——には、sprintf() で文字列を組み立てて cat() に渡します。

%-8s は各名前を8文字に詰め、%6.2f はすべてのスコアを同じ幅と小数2桁にするので、列が揃います。この組み合わせは進捗メッセージや小さなテキストレポートを作る、基本Rの主力です(書式コードは文字列で扱っています)。

message() と warning():もうひとつのチャネル

cat()print()標準出力——プログラムの結果を流すストリーム——に書き込みます。message()warning()標準エラー——実行についての注釈を流すストリーム——に書き込みます。

画面上では似て見えますが、出力をリダイレクトした瞬間にこの分離が効いてきます。スクリプトの標準出力をファイルにパイプすると、42 はファイルに入り、状況を伝えるメモは端末に残ります。これが目安です。結果は cat() で標準出力へ、注釈は message() で標準エラーへ。 関数やパッケージがユーザーに語りかけるとき、cat() ではなく message() が礼儀正しい方法とされる理由でもあります。呼び出す側は suppressMessages() で黙らせても、本当の出力を失わずに済むからです。

warning() はもっと強く、「何かおかしいが、処理は続行した」を意味します。Rscriptでスクリプトを実行すると、警告はその場ではなくまとめて最後に表示されます(読み方はエラーのデバッグを参照)。

ユーザー入力の読み取り:readline() と readLines()

対話セッション(Rコンソールや RStudio)でユーザーに質問するには readline() を使います。以下の例は埋め込みエディタでは実行できません(ページ上のランナーには入力パネルがありません)。ローカルのコンソールで試してみてください。

# Interactive sessions only:
name <- readline("What is your name? ")
cat("Hello,", name, "\n")

age <- as.numeric(readline("Your age? "))
cat("Next year you'll be", age + 1, "\n")

覚えておくことが2つあります。readline() は常に文字列を返すので、計算の前に as.numeric() で変換し、ユーザーが数値でないものを打った場合に備えて結果が NA でないか確認しましょう。そして非対話のスクリプトでは、readline() は入力を待たず、即座に "" を返します。

Rscript で実行するスクリプトでパイプ入力やキーボード入力を読みたい場合は、代わりに標準入力から読み取ります。

# In a script run as: echo "Ada" | Rscript greet.R
line <- readLines(con = "stdin", n = 1)
cat("Hello,", line, "\n")

n を指定しない readLines(con = "stdin") は入力が終わるまですべての行を読みます。フィルタ型スクリプトの定番のかたちです。データファイルの読み込みは別の仕事で、もっと良い道具があります。入力がキーボードではなくデータセットなら、read-csvから始めましょう。

この記事のまとめ

  • 自動表示はトップレベルでのみ起こります。ループや関数の内側では自分で print()cat() を呼びます。
  • print() は調べるためのもの。文字列には引用符、行頭には [1] の添字、エスケープはそのまま表示されます。
  • cat() は見せるためのもの。生のテキストを、引数をスペースでつないで出力し、"\n"あなたが付けます。
  • sprintf() + cat() が、書式を整えて桁を揃える基本Rのパターンです。
  • 結果は標準出力(cat)へ、注釈は標準エラー(messagewarning)へ。
  • 対話的な入力には readline()(返り値は常に文字列!)、Rscriptには readLines(con = "stdin")

次は演算子です。算術、比較、そしてこれから書くあらゆる条件を動かす論理演算子を扱います。

よくある質問

Rのprint()とcat()の違いは何ですか?

print() はRが値を表現するとおりに表示します。文字列は引用符を保ち、各行には [1] のような添字の接頭辞が付きます。cat() は引用符も添字もない生のテキストを書き出し、改行も自動では付きません(自分で "\n" を足します)。オブジェクトを調べるときは print()、人が読む出力を作るときは cat() を使いましょう。

Rのループが何も表示しないのはなぜ?

自動表示が起きるのはトップレベルの式だけです。for ループや関数本体の内側では、裸の x は評価された後、静かに捨てられます。print(x)cat(x, "\n") と明示的に書きましょう。

Rでユーザー入力を読み取るには?

対話セッションでは readline("prompt: ") が入力された1行を文字列として読み取ります(数値が必要なら as.numeric() で変換します)。Rscriptで実行するスクリプトでは readline() は待機しないので、代わりに readLines(con = "stdin", n = 1) で標準入力から読み取ります。

Rで引用符なしに表示するには?

cat("hello\n") を使えば引用符は決して付きません。どうしても print() の挙動のまま引用符を外したい場合は、print("hello", quote = FALSE)noquote("hello") でも実現できます。

Coddy programming languages illustration

Coddyでコードを学ぼう

始める