Textverarbeitung mit R: Die Funktion cat() zum Erzeugen von Ausgaben

Die Funktion cat() bietet die einfachste Möglichkeit, Informationen über ein Objekt oder mehrere Objekte auf der Konsole auszugeben. Die Besonderheiten der Funktion werden vorgestellt, wie etwa spezielle Formatierungsanweisungen oder die Möglichkeit die Ausgabe in eine Datei umzuleiten.

Einordnung des Artikels

Vorausgesetzt werden hier Kenntnisse über Zeichenketten und Vektoren aus Einführung in R: Zeichen und Vektoren in R: der Datentyp vector.

Einführung

Zur Ausgabe des Inhalts beziehungsweise des Datentyps von Variablen werden meist die Funktionen print() und str() eingesetzt. Diese beiden Funktionen sind generisch implementiert und liefern somit eine Ausgabe, die an den jeweiligen Datentyp angepasst ist.

Die Funktion cat() ist deutlich weniger komplex implementiert, ist aber häufig die erste Wahl, wenn man einfache Informationen über Objekte ausgeben möchte. Vorgestellt werden hier:

  1. Die typischen Fälle, bei denen eine einfache Konsolenausgabe erzeugt werden soll, die weniger detailliert ist als die von print() oder str().
  2. Die Funktion cat() besitzt keinen Rückgabewert, so dass sie nicht eingesetzt werden kann, um eine Zeichenkette zu erzeugen, um mit dieser dann weiterzuarbeiten. Hierfür gibt es besser geeignete Funktionen wie paste0() oder paste().
  3. Einige Besonderheiten, die beim Umgang mit cat() zu beachten sind, insbesondere dass einige Zeichen maskiert werden müssen, aber hilfreiche Sonderzeichen wie der Zeilenumbruch \n oder der Tabulator \t eingesetzt werden können.
  4. Es gibt weitere Eingabewerte von cat(), mit denen spezielle Formatierungen der Ausgaben vorgenommen werden können (Trennungszeichen zwischen den Komponenten eines Vektors, Festlegen der Zeilenlänge bei mehrzeiligen Ausgaben sowie Hinzufügen von Labels zu den Zeilen der Ausgabe).
  5. Die Funktion cat() bietet die Möglichkeit, die Ausgaben direkt in eine Datei umzuleiten.

Elementare Verwendung von cat()

Die Aufgabe der Funktion cat() besteht zuallererst darin, Konsolenausgaben zu erzeugen. Es ist nicht ihre Aufgabe Zeichenketten zu erzeugen, um sie später weiterzuverwenden - dazu stellt das R-Basis-Paket andere Funktionen zur Verfügung wie paste0() oder paste().

An das Argument ... werden die Objekte übergeben, die auf der Konsole ausgegeben werden. Handelt es sich um mehr als ein Objekt, werden sie in Zeichenketten verwandelt und zu einem Objekt verkettet (concatenation). Die weiteren Argumente von cat() werden für spezielle Aufgaben zur Verarbeitung der Zeichenkette verwendet.

Die Eingabewerte von cat() mit ihren default-Werten kann man in der Dokumentation nachlesen:

cat(... , file = "", sep = " ", fill = FALSE, labels = NULL, append = FALSE)

Vorerst wird nur die einfachste Anwendung gezeigt, wie man mit Hilfe von cat() Ausgaben auf der Konsole erzeugt und welche Besonderheiten bei speziellen Zeichen beachtet werden müssen. In den folgenden Kapiteln werden dann weitere Argumente von cat() vorgestellt, mit denen sich spezielle Formatierungen realisieren lassen sowie Ausgaben in Dateien geschrieben werden können.

Erzeugen von Konsolenausgaben

Das erste und wichtigste Argument der Funktion cat() ist dot-dot-dot ... . An dieses Argument werden die Objekte übergeben, die auf der Konsole ausgegeben werden sollen.

Wird nur ein Objekt übergeben, so kann dies eine Zeichenkette sein oder ein beliebiges Objekt das zuvor definiert wurde. Werden mehrere Zeichenketten oder Objekte - durch Komma getrennt - an das Argument ... übergeben, so werden sie zu einer Zeichenkette vereinigt. Das folgende Skript ordnet der Variable x den Wert 5 zu und zeigt die typische Verwendung von cat():

x <- 5
y <- 17

cat("Ausgabe: ")
# Ausgabe: 

cat(x)
# 5

cat("x = ", x)
# x =  5

cat("x = ", x, "\ny = ", y)
# x =  5 
# y =  17

Zur Erklärung:

Zeile 4: An das Argument ... wird lediglich eine Zeichenkette übergeben; sie wird unverändert auf der Konsole ausgegeben.

Zeile 7: Die Zahl x wurde gleich 5 gesetzt; wird das Objekt x an ... übergeben, erscheint der Wert 5 von x auf der Konsole.

Zeile 10: Durch ein Komma getrennt werden eine Zeichenkette und ein Objekt an ... übergeben; diese werden verkettet und ausgegeben.

Zeile 13: Man kann selbstverständlich beliebig viele Objekte auf die soeben vorgestellte Weise verketten. Oft werden die Ausgaben dabei sehr unübersichtlich, so dass man einen Zeilenumbruch an einer geeigneten Stelle erzwingen möchte. Dies geschieht durch \n .

Das folgende Skript zeigt wie cat() zur Ausgabe von komplexen Objekten eingesetzt wird beziehungsweise nicht eingesetzt werden kann:

v <- (1:5)
cat("v = ", v)
# v =  1 2 3 4 5
# Zwischen den Komponenten von v wird sep = " " eingesetzt

book <- list(name = "R-expert", title = "Introduction to R", year = 2020)
cat(book)
# Error in cat(book) : argument 1 (type 'list') cannot be handled by 'cat'

Zeile 1 bis 4: Wird ein Vektor ausgegeben, so werden die einzelnen Komponenten durch ein Leerzeichen getrennt ausgegeben. Das Leerzeichen ist der default-Wert des Argumentes sep = " " , weitere Beispiele werden unten gezeigt, wenn dieses Argument besprochen wird.

Zeile 6 bis 8: In Zeile 6 wird eine Liste definiert, die aus zwei Zeichenketten und einer Zahl zusammengesetzt ist. An der Fehlermeldung erkennt man jetzt, dass die Implementierung der Funktion cat() nicht komplex genug ist, um derartige Objekte zu verarbeiten. Hier muss man auf die entsprechenden Diagnosefunktionen zurückgreifen oder man muss sich überlegen, wie sich durch eine Iteration über die Komponenten eine geeignete Ausgabe erzeugen lässt.

Der Rückgabewert von cat()

Die Funktion cat() besitzt keinen Rückgabewert, genauer den Rückgabewert NULL. Daran kann man ablesen, dass die von cat() erzeugte Zeichenkette nicht weiterverwendet werden kann. Für diese Aufgabe gibt es andere Funktionen, die ansonsten ähnliche Eigenschaften Funktionalitäten besitzen wie cat(), etwa paste0() und paste(), die hier nicht besprochen werden.

z <- cat("x")
str(z)
# NULL

Spezielle Zeichen in Zeichenketten

Bei der Verwendung von Zeichenketten ist zu beachten, dass gewisse Symbole nicht verwendet werden können. Zum Beispiel werden die Anführungsstriche als Begrenzer einer Zeichenkette eingesetzt - würde man Anführungsstriche innerhalb einer Zeichenkette verwenden, könnte man sie nicht von den Begrenzern unterscheiden und die Zeichenkette ist nicht eindeutig definiert.

Die folgende Tabelle zeigt die wichtigsten Zeichen, die innerhalb einer Zeichenkette verwendet werden können, die aber - wie man sagt - maskiert werden müssen. Zum Maskieren wird der backslash \ verwendet; als Zeichen für eine Maskierung kann er dann auch nicht innerhalb einer Zeichenkette vorkommen. Um innerhalb einer Zeichenkette einen backslash zu erzeugen muss \\ verwendet werden, das heißt der backslash ist zugleich das Maskierungszeichen für den backslash.

\\" Anführungsstrich
\\\\ backslash
\\n Zeilenumbruch
\\t Tabulator (horizontal)

Spezielle Formatierungen

Das Argument sep

Oben wurde schon gezeigt, dass die Funktion cat() in de Lage ist, auch zusammengesetzte Objekte (wie Vektoren) auszugeben. Erst wenn die Objekte zu komplex sind - etwa Listen - muss man eine andere Möglichkeit für eine geeignete Ausgabe finden.

Der default-Wert des Argumentes sep ist das Leerzeichen: sep = " " . Um etwa ganzzahlige Vektoren auszugeben, reicht dies meist aus. Die Komponenten werden der Reihe nach ausgegeben und durch das Leerzeichen getrennt. Bei Fließkommazahlen kann dies oft zu Problemen führen, da es schwer vorauszusagen ist, wo der Zeilenumbruch stattfinden wird.

Das folgende Skript zeigt einige Beispiele, in denen spezielle Ausgaben erzeugt werden:

v <- (1:5)
w <- v * pi

cat("v = ", v, sep = " | ")
# v =  | 1 | 2 | 3 | 4 | 5

cat(w)
# 3.141593 6.283185 9.424778 12.56637 15.70796

cat(w, sep ="\n")
# 3.141593
# 6.283185
# 9.424778
# 12.56637
# 15.70796

m <- cbind(v, w)
str(m)
# num [1:5, 1:2] 1 2 3 4 5 ...
#   - attr(*, "dimnames")=List of 2
#   ..$ : NULL
#   ..$ : chr [1:2] "v" "w"
cat(m)
# 1 2 3 4 5 3.141593 6.283185 9.424778 12.56637 15.70796

m <- rbind(v, w)
str(m)
# num [1:2, 1:5] 1 3.14 2 6.28 3 ...
#   - attr(*, "dimnames")=List of 2
#   ..$ : chr [1:2] "v" "w"
#   ..$ : NULL
cat(m, sep = " | ")
# 1 | 3.141593 | 2 | 6.283185 | 3 | 9.424778 | 4 | 12.56637 | 5 | 15.70796

Zeile 1 und 2: Es werden zwei Vektoren definiert, nämlich v mit den ganzen Zahlen von 1 bis 5, sowie w mit den entsprechenden Vielfachen von π.

Zeile 4 und 5: Anstelle des default-Wertes von sep wird jetzt explizit zur Ausgabe von v gesetzt: sep = " | " . Der Trennungsstrich soll das Lesen erleichtern.

Man beachte, dass die Zeichenkette, die dem Argument sep übergeben wird, vor jeder Komponente des Vektors ausgegeben wird. Der Name sep ist missverständlich, da man annehmen könnte, dass es sich um einen Separator handelt, der nur zwischen den Komponenten ausgegeben wird.

Zeile 7 und 8: Gibt man den Vektor w der Fließkommazahlen mit dem default-Wert von sep aus, so ist die Ausgabe schon mühsam zu lesen.

Zeile 10 bis 15: Da man bei langen Ausgaben schwer vorhersagen kann, wo genau der Zeilenumbruch stattfindet, kann man den Zeilenumbruch leicht erzwingen, indem man sep = "\n" setzt.

Zeile 17 bis 24: Verknüpft man die Vektoren v und w mit cbind() zu einer Matrix, so entsteht eine Matrix mit 5 Zeilen und zwei Spalten. Man erkennt in Zeile 24, dass auch einen Matrix ein möglicher Eingabewert für das Argument ... ist. Wird sep nicht explizit gesetzt, werden die Komponenten der Matrix ausgegeben, indem sie durch ein Leerzeichen getrennt werden. Dabei ist zu beachten, dass die Matrix spaltenweise ausgegeben wird.

Zeile 26 bis 33: Jetzt wird die Matrix mit Hilfe der Funktion rbind() aus v und w gebildet, es entsteht eine Matrix mit 2 Zeilen und 5 Spalten. Zur Ausgabe wird wieder sep = " | " gesetzt. Die Ausgabe erfolgt wieder spaltenweise.

Man erkennt an den letzten beiden Beispielen, dass die Verwendung von cat() leicht zur Verwirrung führen kann, wenn man sich nicht bewusst ist, dass die Ausgabe spaltenweise erfolgt - hier ist eine Funktion wie print() in vielen Fällen besser geeignet.

Das Argument fill

Wird ein cat()-Befehl ausgeführt, so wird versucht, die gesamte Zeichenkette in eine Zeile der Konsole zu schreiben. Je nach aktueller Größe der Konsole wird die Ausgabe an unterschiedlichen Stellen umgebrochen. (Man hat dieses Verhalten von cat() bereits oben bei der Ausgabe einer Matrix gesehen - die Ausgabe, die von print() erzeugt wird, ist hier besser an das auszugebende Objekt angepasst.)

Im folgenden Skript wird der Vektor der Zahlen von 1 bis 100 ausgegeben, wobei der default-Wert des Argumentes fill = FALSE explizit angegeben wird. Wie viele der Zahlen in einer Zeile erscheinen werden, hängt von der aktuellen Größe der Konsole ab.

cat(1:100, fill = FALSE)

Gerade bei umfangreichen Ausgaben kann es sinnvoll sein, die Zeilenlänge vorzugeben, so dass nach einer bestimmten Anzahl von Zeichen ein Zeilenumbruch erzwungen wird. Das folgende Skript zeigt zwei Ausgaben des Vektors 1:100 mit 50 beziehungsweise 80 Zeichen pro Zeile:

cat(1:100, fill = 50)
# 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 
# 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 
# 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 
# 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 
# 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 
# 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 
# 100

cat(1:100, fill = 80)
# 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 
# 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 
# 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 
# 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100

Das Argument labels

Um das Argument labels besser zu verstehen, wird im folgenden Skript ein Vektor (1:200) mit Hilfe der Funktion print() ausgegeben. Die Zahlen in eckigen Klammern jeweils am Beginn einer Zeile sind natürlich keine Komponenten des Vektors (1:200) . Ihre Aufgabe ist es anzugeben, welche Komponente in der entsprechenden Zeile an führender Stelle gezeigt wird.

print(1:200)
# [1]   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21  22
# [23]  23  24  25  26  27  28  29  30  31  32  33  34  35  36  37  38  39  40  41  42  43  44
# [45]  45  46  47  48  49  50  51  52  53  54  55  56  57  58  59  60  61  62  63  64  65  66
# [67]  67  68  69  70  71  72  73  74  75  76  77  78  79  80  81  82  83  84  85  86  87  88
# [89]  89  90  91  92  93  94  95  96  97  98  99 100 101 102 103 104 105 106 107 108 109 110
# [111] 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
# [133] 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
# [155] 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
# [177] 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
# [199] 199 200

Derartige labels, deren Aufgabe es ist, die Ausgabe näher zu erläutern, kann man für Ausgaben mit cat() mit Hilfe des Argumentes labels = NULL erzeugen.

Das folgende Skript definiert mit Hilfe der Funktion paste0() einen Vektor lbl mit den Zeichenketten "1: " , "2: " , ...., "8: " (siehe Zeile 1 und 2). Wird jetzt der Vektor (1:200) mit cat() ausgegeben, wobei das Argument labels = lbl gesetzt wird, so werden an die Zeilen der Ausgabe die Zeichenketten aus lbl vorangestellt (siehe Zeile 4 bis 12).

lbl <- paste0((1:8), ": ")
# [1] "1: " "2: " "3: " "4: " "5: " "6: " "7: " "8: "

cat((1:200), fill = TRUE, labels = lbl)
# 1:  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 
# 2:  34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 
# 3:  64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 
# 4:  94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 
# 5:  118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 
# 6:  140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 
# 7:  162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 
# 8:  184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200

Achtung: Die labels werden nur erzeugt, wenn ausdrücklich fill = TRUE gesetzt wird.

Schreiben in eine Datei

Das Konzept der connection

Mit dem Argument file wird im Allgemeinen eine connection angesprochen und in diese wird die von cat() erzeugte Ausgabe weitergeleitet. Der default-Wert für file = "" ist die leere Zeichenkette, sie steht dafür, dass die Ausgabe an die Konsole weitergeleitet wird.

Im Allgemeinen wird mit dem Argument file eine connection oder eine "verallgemeinerte Datei" angesprochen. In der R-Dokumentation wird eine connection erklärt durch:

"generalized files, such as possibly compressed files, URLs, pipes, etc."

Im folgenden wird nur der einfachste Fall erklärt, wenn die Ausgabe in einen Datei geschrieben wird.

Umleiten der Ausgabe in eine Datei

Das folgende Skript zeigt den Einsatz des Argumentes file in der Funktion cat(), um eine Zeichenkette in eine Datei zu schreiben, und die beiden Möglichkeiten wie das Argument append eingesetzt wird:

v <- (1:5)
output <- "C:\\R\\work\\output.txt"

cat("v = \n", v, file = output)

# Im File output.txt:
# v = 
#   1 2 3 4 5

cat("v = \n", v, file = output, append = TRUE)

Zeile 1 und 2: Der Vektor v enthält wieder die Zahlen von 1 bis 5. In der Variable output wird eine Zeichenkette abgespeichert, die einen absoluten Pfad im Dateisystem beschreibt. Die Trennungszeichen zwischen den Ordnern sind eigentlich backslash-Symbole, sie müssen wie oben besprochen durch einen weiteren backslash maskiert werden.

Zeile 4: Die Variable output wird an das Argument file von cat() übergeben. Da der default-Wert append = FALSE verwendet wird, bewirkt der Aufruf von cat() folgendes:

  1. Ist die Datei output.txt im angegebenen Ordner noch nicht vorhanden, wird sie erzeugt und geöffnet.
  2. Die Zeichenkette im Argument ... von cat() wird in die Datei geschrieben.
  3. Die Datei wird geschlossen.
  4. Tritt bei den genannten Operationen ein Fehler auf, erfolgt eine Fehlermeldung auf der Konsole.
  5. War die Datei output.txt im angegebenen Ordner bereits vorhanden, so wird sie zunächst gelöscht und dann erfolgen die soeben beschriebenen Anweisungen 1. bis 4.

Zeile 7 und 8: In der Datei output.txt befinden sich jetzt die gezeigten Ausgaben (natürlich ohne das # -Symbol, das hier verwendet wird, um einen Kommentar zu erzeugen).

Zeile 10: Wird cat() mit append = TRUE aufgerufen, so geschieht folgendes:

  1. Die Datei output.txt wird geöffnet. Falls sie noch nicht existiert hat, wird sie erzeugt.
  2. An das Ende der Datei wird die Zeichenkette aus dem Argument ... geschrieben.
  3. Die Datei wird geschlossen.
  4. Falls Fehler auftreten, gibt es wieder Fehlermeldungen auf der Konsole.

Da in diesem Fall die Datei zweimal beschrieben wurde, enthält sie jetzt zweimal die Ausgabe des Vektors v. Dabei ist aber zu beachten, dass weder die erste Ausgabe mit einem Zeilenumbruch endet noch die zweite Ausgabe mit einen Zeilenumbruch beginnt. Die Zeichenkette der zweiten Ausgabe wird aber unmittelbar an das Ende der Datei angehängt, so dass ihr Inhalt jetzt aussieht wie im folgenden Skript:

v = 
 1 2 3 4 5v = 
 1 2 3 4 5

Als Trennungszeichen zwischen den Ordnern kann auch das Symbol / verwendet werden; es muss nicht maskiert werden. Zeile 2 im obigen Skript lautet dann:

output <- "C:/R/work/output.txt"