Menu

Wypisywanie danych i wczytywanie wejścia w R (print, cat, readline)

Jak działa wypisywanie w R: automatyczne wyświetlanie, print() kontra cat(), message(), oraz jak wczytać dane od użytkownika przez readline() i readLines().

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

Jak działa wypisywanie w R

R ma zwyczaj, którego nie ma żaden inny popularny język: w konsoli w ogóle nie potrzebujesz instrukcji wypisywania. Wpisz nazwę zmiennej, naciśnij Enter, a R wypisze jej wartość. To automatyczne wyświetlanie (ang. auto-printing) i właśnie dlatego poradniki R są pełne samych wyrażeń.

Automatyczne wyświetlanie ma jednak ścisłą granicę: działa tylko dla wyrażeń na najwyższym poziomie. Wewnątrz pętli for albo ciała funkcji sama wartość jest obliczana i po cichu wyrzucana:

Samotne x zostaje wypisane (jest na najwyższym poziomie), pierwsza pętla nie wypisuje nic, a druga wypisuje 1, 2, 3, bo prosi o to jawnie. "Moja pętla działa, ale nic nie pokazuje" to jedno z najczęstszych pytań o R i to jest cała odpowiedź: wewnątrz pętli i funkcji wypisywanie zawsze należy do ciebie. (To samo dotyczy uruchamiania skryptu przez Rscript: coś, co działało linia po linii w konsoli, w pętli może zamilknąć.)

print() pokazuje wartość tak, jak widzi ją R. Dzięki temu to właściwe narzędzie do podglądania danych i niewłaściwe do dopracowanego wyjścia:

Rzucają się w oczy dwie rzeczy. Napisy zachowują cudzysłowy: print() pokazuje wierną reprezentację, a cudzysłowy mówią, że to wartość tekstowa. Poza tym każda linia zaczyna się od liczby w nawiasach kwadratowych, np. [1]: to indeks pierwszego elementu w tej linii. Gdy długi wektor zawija się na kolejne linie, nawias w każdej linii mówi, od którego elementu ona startuje. To pomoc w czytaniu wektorów, a nie szum.

Jeśli chcesz wyjścia w stylu print() bez cudzysłowów, zadziałają zarówno print(x, quote = FALSE), jak i noquote(x). Zwykle jednak w takiej sytuacji naprawdę potrzebujesz cat().

cat(): wyjście dla ludzi

cat() (od concatenate-and-print) wypisuje surowy tekst: bez cudzysłowów, bez prefiksów z indeksami, a argumenty łączy spacjami. Ceną tej kontroli jest to, że nic nie jest dodawane za ciebie, łącznie ze znakiem nowej linii:

Zapomniane "\n" to obowiązkowy rytuał przejścia przy cat(): bez niego kolejny fragment wyjścia skleja się z tą samą linią. Niech kończenie wywołań cat() przez "\n" wejdzie ci w odruch.

Różnica z cudzysłowami to tak naprawdę różnica w tym, co obie funkcje pokazują. print() wyświetla sekwencje ucieczki tak, jak je wpisano, a cat() je interpretuje:

print() pokazuje \t i \n dosłownie w cudzysłowach, co przydaje się, gdy sprawdzasz, co dokładnie zawiera napis. cat() zamienia je na prawdziwą tabulację i prawdziwy podział linii, co przydaje się, gdy tworzysz wyjście. Wybieraj według celu: print() do podglądu, cat() do prezentacji.

Sformatowane raporty: sprintf() + cat()

Argumenty cat() rozdzielane spacjami mają swoje granice. Do wyrównanego, sformatowanego wyjścia (stała liczba miejsc po przecinku, wyrównane liczniki) zbuduj napis przez sprintf() i przekaż go do cat():

%-8s dopełnia każde imię do 8 znaków, a %6.2f daje każdemu wynikowi tę samą szerokość i dwa miejsca po przecinku, więc kolumny się wyrównują. Ta para to podstawowe narzędzie bazowego R do komunikatów o postępie i małych raportów tekstowych (kody formatowania opisuje artykuł o napisach).

message() i warning(): drugi kanał

cat() i print() piszą na standardowe wyjście (stdout), czyli strumień z wynikami programu. message() i warning() piszą na standardowe wyjście błędów (stderr), czyli strumień z komentarzami o przebiegu działania:

Na ekranie oba wyglądają podobnie, ale rozdział ma znaczenie, gdy tylko przekierujesz wyjście: skieruj stdout skryptu do pliku, a 42 trafi do pliku, podczas gdy notatka o stanie zostanie w terminalu. Stąd praktyczna zasada: wyniki na stdout przez cat(), komentarze na stderr przez message(). To też powód, dla którego message() (a nie cat()) jest uprzejmym sposobem, w jaki funkcje i pakiety komunikują się z użytkownikami: wywołujący może je wyciszyć przez suppressMessages() bez utraty właściwego wyjścia.

warning() jest mocniejsze ("coś jest nie tak, ale działam dalej"). Gdy skrypt działa pod Rscript, ostrzeżenia są zbierane i pokazywane razem na końcu, a nie w miejscu wystąpienia (jak je czytać, opisuje artykuł o debugowaniu błędów).

Wczytywanie wejścia: readline() i readLines()

Żeby zadać użytkownikowi pytanie w sesji interaktywnej (konsola R albo RStudio), użyj readline(). Tych przykładów nie da się uruchomić we wbudowanym edytorze, bo edytor na stronie nie ma panelu wejścia, więc wypróbuj je w lokalnej konsoli:

# 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")

Zapamiętaj dwie rzeczy. readline() zawsze zwraca napis: przekonwertuj go przez as.numeric(), zanim zaczniesz liczyć, i sprawdź wynik pod kątem NA na wypadek, gdyby użytkownik wpisał coś, co nie jest liczbą. Poza tym w nieinteraktywnym skrypcie readline() w ogóle nie czeka na wejście, tylko od razu zwraca "".

W skrypcie uruchamianym przez Rscript, który ma czytać wejście przekazane potokiem albo wpisane z klawiatury, czytaj ze standardowego wejścia:

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

readLines(con = "stdin") bez n czyta wszystkie linie aż do końca wejścia, co jest typowym kształtem skryptów działających jak filtry. Wczytywanie plików z danymi to inne zadanie z lepszymi narzędziami; zacznij od read-csv, gdy twoim wejściem jest zbiór danych, a nie klawiatura.

Co warto zapamiętać

  • Automatyczne wyświetlanie działa tylko na najwyższym poziomie: wewnątrz pętli i funkcji wywołuj print() albo cat() samodzielnie.
  • print() służy do podglądu: cudzysłowy przy napisach, prefiksy z indeksem [1], sekwencje ucieczki pokazane dosłownie.
  • cat() służy do prezentacji: surowy tekst, argumenty łączone spacjami, a "\n" dodajesz ty.
  • sprintf() + cat() to wzorzec bazowego R do sformatowanego, wyrównanego wyjścia.
  • Wyniki idą na stdout (cat), komentarze na stderr (message, warning).
  • readline() do wejścia interaktywnego (zawsze napis!), readLines(con = "stdin") do Rscript.

Dalej: operatory, czyli arytmetyka, porównania i operatory logiczne, na których opiera się każdy warunek, jaki napiszesz.

Najczęściej zadawane pytania

Czym różni się print() od cat() w R?

print() pokazuje wartość tak, jak reprezentuje ją R: napisy zachowują cudzysłowy, a każda linia dostaje prefiks z indeksem w stylu [1]. cat() wypisuje surowy tekst bez cudzysłowów, bez indeksów i bez automatycznego znaku nowej linii (dodajesz "\n" samodzielnie). Używaj print() do podglądania obiektów, a cat() do tworzenia wyjścia dla ludzi.

Dlaczego moja pętla w R nic nie wypisuje?

Automatyczne wyświetlanie działa tylko dla wyrażeń na najwyższym poziomie. Wewnątrz pętli for albo ciała funkcji samo x zostaje obliczone i po cichu odrzucone. Wypisz je jawnie: print(x) albo cat(x, "\n").

Jak wczytać dane od użytkownika w R?

W sesji interaktywnej readline("prompt: ") wczytuje jedną wpisaną linię jako napis (jeśli potrzebujesz liczby, przekonwertuj ją przez as.numeric()). W skrypcie uruchamianym przez Rscript readline() nie czeka na wejście, więc czytaj ze standardowego wejścia przez readLines(con = "stdin", n = 1).

Jak wypisać tekst bez cudzysłowów w R?

Użyj cat("hello\n"), bo ta funkcja nigdy nie dodaje cudzysłowów. Jeśli zależy ci konkretnie na zachowaniu print() bez cudzysłowów, działają też print("hello", quote = FALSE) i noquote("hello").

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ