Strings und reguläre Ausdrücke (Regex)

Strings und reguläre Ausdrücke (Regex)

Strings (Zeichenketten) sind Informationen, die aus Ziffern, Symbolen und/oder Buchstaben bestehen. Ein String kann also eine Mischung aus diesen Komponenten sein. In R wird ein String mithilfe von Anführungszeichen definiert. Im Folgenden wird ein String definiert und im Objekt my_string gespeichert:

## Einen String in einem Objekt speichern
my_string <- "Detta är en sträng!"

## Das Objekt ausgeben
my_string
[1] "Detta är en sträng!"

Bevor wir fortfahren, laden wir das Package tidyverse, das das Package stringr enthält, in dem sich alle Funktionen befinden, die für die Arbeit mit Strings benötigt werden.

library(tidyverse)
── Attaching packages ─────────────────────────────────────── tidyverse 1.3.2 ──
 ggplot2 3.3.6       purrr   0.3.4
 tibble  3.1.8       dplyr   1.0.10
 tidyr   1.2.0       stringr 1.4.1
 readr   2.1.2       forcats 0.5.1
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
 dplyr::filter() masks stats::filter()
 dplyr::lag()    masks stats::lag()

Mehrere Strings lassen sich mit der Funktion [c()](https://rdrr.io/r/base/c.html) definieren, die mehrere Elemente zu einem Vektor kombiniert:

my_string <- c("Detta är en sträng!", "Detta är en annan sträng")

my_string
[1] "Detta är en sträng!"      "Detta är en annan sträng"

Die obigen Strings wurden mit doppelten Anführungszeichen (" ") erstellt. Strings können aus einem einzigen Zeichen bestehen oder ganze Bücher enthalten. Im Folgenden werden drei Strings definiert: ein kurzer String (my_string_short), ein String, der nur aus Ziffern besteht (my_string_numbers), und ein langer String (my_string_long):

## Ein kurzer String
my_string_short <- c("Detta är en sträng!")

## Ein String nur mit Ziffern
my_string_numbers <- c("123")

## Ein langer String
my_string_long <- c("Salvador Domingo Felipe Jacinto Dalí i Domènech, 1:e markis av Púbol, född 11 maj 1904 i Figueres, Katalonien, Spanien, död 23 januari 1989 i Figueres, var en katalansk (spansk) surrealistisk konstnär. Dalí är mest känd för sina bisarra, absurda och drömska målningar, influerade av bland annat Freuds psykoanalys, Einsteins relativitetsteorier och renässansmåleri.[2][3] Ett av hans mest kända verk, Minnets envishet, blev klart 1931. Utöver måleri omfattade Dalís praktik även film, skulptur, fotografi och text. Han samarbetade med Walt Disney kring den Oscars-nominerade tecknade kortfilmen Destino, som släpptes postumt 2003. Han samarbetade också med Alfred Hitchcock i arbetet med filmen Trollbunden.")

Strings und Anführungszeichen

Verwenden Sie doppelte Anführungszeichen (""), wenn Sie einen String definieren. Verwenden Sie einfache Anführungszeichen ('') nur, um einen String zu definieren, der doppelte Anführungszeichen enthält.

Ein String kann auch mit einfachen Anführungszeichen (' ') erstellt werden:

my_string <- c('Detta är en sträng!')
my_string
[1] "Detta är en sträng!"

Es wird jedoch empfohlen, Strings mit doppelten Anführungszeichen zu definieren.

Versuchen wir, einen String zu definieren, der Anführungszeichen enthält:

my_string <- c("Han fick smeknamnet "Yoggi" men det gillade han inte")
my_string
Error: unexpected symbol in "my_string <- c("Han fick smeknamnet "Yoggi"

Es tritt ein Error (Fehler) auf, weil R nicht weiß, wie die Anführungszeichen um Yoggi ("Yoggi") zu interpretieren sind. Das liegt daran, dass Anführungszeichen in Strings eine besondere Bedeutung haben, nämlich Anfang und Ende des Strings zu kennzeichnen. R nimmt an, dass der String beim ersten Anführungszeichen vor dem Buchstaben Y ("Y..) endet, da auf dieses Anführungszeichen aber weitere Buchstaben folgen, entsteht ein Error. Wir brauchen folglich eine Methode, um R mitzuteilen, dass die Anführungszeichen im String tatsächlich Teil des Strings sind und kein Zeichen mit einer besonderen Funktion! Es gibt weitere Zeichen (., *, ] usw.), die eine solche Mehrdeutigkeit verursachen können, sodass ein Error auftritt.

Um diese Mehrdeutigkeit zu vermeiden, wird der umgekehrte Schrägstrich (\, *Backslash*) verwendet. Der Backslash teilt R mit, dass die Anführungszeichen um „Yoggi“ als Teil des Strings betrachtet werden sollen. Das bedeutet, dass der Backslash (\) verwendet wird, um die besondere Funktion des Anführungszeichens aufzuheben (engl. escape). Versuchen wir, den String noch einmal einzulesen, diesmal mit \ vor jedem Anführungszeichen im String:

my_string <- c("Han fick smeknamnet \"Ylle\" men det gillade han inte")

Das hat ohne Error funktioniert! Geben wir den String aus:

my_string
[1] "Han fick smeknamnet \"Ylle\" men det gillade han inte"

Beachten Sie, dass der Backslash (\) bei der Ausgabe des Strings angezeigt wird. Der Grund dafür ist, dass R kenntlich macht, wo ein Escape verwendet wurde. Wenn Sie einen String ohne Escape (\) ausgeben möchten (engl. print), verwenden Sie die Funktion [writeLines()](https://rdrr.io/r/base/writeLines.html):

writeLines(my_string)
Han fick smeknamnet "Ylle" men det gillade han inte

Ebenso muss einfachen Anführungszeichen ein \ vorangestellt werden, um Mehrdeutigkeit zu vermeiden:

my_string <- c('Han fick smeknamnet \'Ylle\' men det gillade han inte')
writeLines(my_string)
Han fick smeknamnet 'Ylle' men det gillade han inte

Speziell bei Anführungszeichen lässt sich Mehrdeutigkeit auch vermeiden, indem man den String mit doppelten Anführungszeichen definiert und innerhalb des Strings einfache Anführungszeichen verwendet, oder umgekehrt. Ein Beispiel folgt:

my_string1 <- c("Han fick smeknamnet 'Svurre' men det gillade han inte")
writeLines(my_string)
Han fick smeknamnet 'Svurre' men det gillade han inte
my_string2 <- c('Han fick smeknamnet "Svurre" men det gillade han inte')
writeLines(my_string)
Han fick smeknamnet 'Svurre' men det gillade han inte

Die folgende Tabelle zeigt weitere Sonderzeichen und Formatierungen, bei denen ein Escape nötig ist, um Mehrdeutigkeit zu vermeiden:

Escape character Bedeutung
\n newline
\r carriage return
\t tab
\b backspace
\a alert (bell)
\f form feed
\v vertical tab
\\ backslash \
\’ ASCII apostrophe ’
\” ASCII quotation mark ”
\` ASCII grave accent (backtick) `
\nnn character with given octal code (1, 2 or 3 digits)
\xnn character with given hex code (1 or 2 hex digits)
\unnnn Unicode character with given code (1--4 hex digits)
\Unnnnnnnn Unicode character with given code (1--8 hex digits)

8.1 Stringr und reguläre Ausdrücke (Regex)

Das Package stringr enthält alle notwendigen Funktionen, um in R mit Strings zu arbeiten. Im Folgenden werden die wichtigsten Funktionen besprochen und anschließend, wie reguläre Ausdrücke (regular expressions) genutzt werden können, um leistungsfähige Treffer in Strings zu erzielen. Die meisten Funktionen in stringr haben das Präfix str_. Beginnen wir damit, einen String zu definieren:

my_string <- c("Det är roligt att lära sig R!")

8.1.1 Identische Strings

Wir erstellen nun zwei Vektoren, die aus einem identischen String („Sommarlov“) bestehen, und verwenden die Funktion [identical()](https://rdrr.io/r/base/identical.html), um festzustellen, ob sie identisch sind:

word_1 <- "Sommarlov"
word_2 <- "Sommarlov"
identical(word_1, word_2)
[1] TRUE

Wie bei vielen anderen R-Funktionen können Sie ein Ausrufezeichen (!) vor den Funktionsnamen setzen, um den gegenteiligen Effekt zu erzielen. Wenn die Funktion [identical()](https://rdrr.io/r/base/identical.html) klärt, ob zwei Strings identisch sind, dann klärt [identical()](https://rdrr.io/r/base/identical.html), ob die Strings nicht identisch sind. Wir prüfen nun, ob die Wörter nicht identisch sind:

!identical(word_1, word_2)
[1] FALSE

8.1.2 Groß- und Kleinschreibung ändern

Mit den Funktionen [str_to_lower()](https://stringr.tidyverse.org/reference/case.html), [str_to_sentence()](https://stringr.tidyverse.org/reference/case.html), [str_to_title()](https://stringr.tidyverse.org/reference/case.html) und [str_to_upper()](https://stringr.tidyverse.org/reference/case.html) aus dem Package stringr können Sie die Groß- und Kleinschreibung eines Strings wie folgt ändern:

## Wandelt Buchstaben in Kleinbuchstaben um
str_to_lower(my_string)
[1] "det är roligt att lära sig r!"
## Wandelt den String in Satzschreibweise um
str_to_sentence(my_string)
[1] "Det är roligt att lära sig r!"
## Wandelt den String in Titelschreibweise um
str_to_title(my_string)
[1] "Det Är Roligt Att Lära Sig R!"
## Wandelt Buchstaben in Großbuchstaben um
str_to_upper(my_string)
[1] "DET ÄR ROLIGT ATT LÄRA SIG R!"

8.1.3 Länge eines Strings

Die Länge (Anzahl der Zeichen) eines Strings lässt sich mit [str_length()](https://stringr.tidyverse.org/reference/str_length.html) berechnen:

str_length(my_string)
[1] 29

Wie alle anderen Funktionen in stringr ist [str_length()](https://stringr.tidyverse.org/reference/str_length.html) vektorisiert. Das bedeutet, dass die Berechnung für jedes Element des Vektors durchgeführt wird, wenn Sie die Funktion auf einen Vektor anwenden:

str_length(c("Hej", "Ja", "Kanske"))
[1] 3 2 6

8.1.4 Positionen in Strings

Wir können ermitteln, an welcher Stelle im String sich ein bestimmtes Zeichen befindet. Dies geschieht mit der Funktion [str_locate()](https://stringr.tidyverse.org/reference/str_locate.html). Das folgende Beispiel berechnet, an welcher Position der Buchstabe „t“ steht, sofern er vorkommt:

my_string <- c("Det är roligt att lära sig R!")
str_locate(my_string, 't')
     start end
[1,]     3   3

Laut dem Ergebnis wurde „t“ zwischen Position 3 und 3 gefunden, was bedeutet, dass der Buchstabe das dritte Zeichen im String ist. Beachten Sie jedoch, dass der String mehrere „t“ enthält. Um alle zu finden, müssen wir die Funktion [str_locate_all()](https://stringr.tidyverse.org/reference/str_locate.html) verwenden:

str_locate_all(my_string, 't')
[[1]]
     start end
[1,]     3   3
[2,]    13  13
[3,]    16  16
[4,]    17  17

Wir sehen, dass es insgesamt 4 „t“ gibt und dass sie als Zeichen 3, 13, 16 und 17 vorkommen.

8.1.5 Strings sortieren

Zum Sortieren eines Character-Vektors wird die Funktion [str_sort()](https://stringr.tidyverse.org/reference/str_order.html) verwendet:

my_names <- c('Benny', 'Adam', 'Caesar')
str_sort(my_names)
[1] "Adam"   "Benny"  "Caesar"

Nun erstellen wir einen Data Frame mit Vor- und Nachnamen. Von hier an verwenden wir Funktionen aus dem Package dplyr, um Spalten zu erstellen und zu verändern.

## Erstellt Vornamen
first_name <- c('Maria', 'Mohammed', 'Magnus')

## Erstellt Nachnamen
last_name <- c('Svensson', 'Ayman', 'Bentzel')

## Kombiniert zu einem Tibble (Data Frame)
my_data <- tibble(first_name, last_name)

## Gibt unseren Data Frame aus
my_data
## A tibble: 3 × 2
  first_name last_name
  <chr>      <chr>
1 Maria      Svensson
2 Mohammed   Ayman
3 Magnus     Bentzel

8.1.6 Strings kombinieren

Wir fügen Vor- und Nachnamen mit der Funktion [str_c()](https://stringr.tidyverse.org/reference/str_c.html) zu einem String zusammen. Die Funktion hat das Argument sep, das angibt, welches Zeichen die Strings trennen soll. Wir trennen die Strings mit einem Leerzeichen.

Beispiel mit Base R (nicht dplyr):

my_data$full_name <- str_c(my_data$first_name,
                           my_data$last_name,
                           sep = " ")

my_data
## A tibble: 3 × 3
  first_name last_name full_name
  <chr>      <chr>     <chr>
1 Maria      Svensson  Maria Svensson
2 Mohammed   Ayman     Mohammed Ayman
3 Magnus     Bentzel   Magnus Bentzel

Beispiel mit dplyr:

my_data %>%
  mutate(full_name = str_c(first_name, last_name, sep = " "))
## A tibble: 3 × 3
  first_name last_name full_name
  <chr>      <chr>     <chr>
1 Maria      Svensson  Maria Svensson
2 Mohammed   Ayman     Mohammed Ayman
3 Magnus     Bentzel   Magnus Bentzel

Mit dplyr erhalten wir sauberen und einfachen Code, ohne $, [] oder Ähnliches zu verwenden. Neue Spalten werden mit der Funktion mutate(). erstellt.

Mit [str_c()](https://stringr.tidyverse.org/reference/str_c.html) können Sie auch mehr als zwei Strings zusammenfügen:

a = "Hej"
b = "jag"
c = "heter"
d = "Adam"

str_c(a, b, c, d, sep = " ")
[1] "Hej jag heter Adam"

8.1.7 Anzahl der Treffer in einem String zählen

Mit [str_count()](https://stringr.tidyverse.org/reference/str_count.html) können wir berechnen, wie oft ein bestimmter String oder ein bestimmtes Zeichen in einem String vorkommt. Prüfen wir, wie oft der Buchstabe ‘m’ in den Vornamen vorkommt. Dafür erstellen wir eine neue Variable, die wir antal_m nennen:

my_data %>%
  mutate(antal_m = str_count(first_name, 'm'))
## A tibble: 3 × 4
  first_name last_name full_name      antal_m
  <chr>      <chr>     <chr>            <int>
1 Maria      Svensson  Maria Svensson       0
2 Mohammed   Ayman     Mohammed Ayman       2
3 Magnus     Bentzel   Magnus Bentzel       0

R unterscheidet zwischen Groß- und Kleinschreibung. Der Buchstabe m ist nicht gleichbedeutend mit dem Buchstaben M. Wir versuchen es noch einmal mit dem Buchstaben M:

my_data %>%
  mutate(antal_m = str_count(first_name, 'M'))
## A tibble: 3 × 4
  first_name last_name full_name      antal_m
  <chr>      <chr>     <chr>            <int>
1 Maria      Svensson  Maria Svensson       1
2 Mohammed   Ayman     Mohammed Ayman       1
3 Magnus     Bentzel   Magnus Bentzel       1

8.1.8 Strings, Zeichen und Symbole in Strings erkennen

Mit der Funktion [str_detect()](https://stringr.tidyverse.org/reference/str_detect.html) können wir feststellen, ob Ziffern, Buchstaben, Symbole, Zeichen oder Strings in einem String vorkommen. Die Funktion [str_detect()](https://stringr.tidyverse.org/reference/str_detect.html) gibt einen booleschen Wert (TRUE, FALSE) zurück. Wir erstellen nun die Variable finns_m, die angibt, ob der Buchstabe "m" im String enthalten ist:

my_data %>%
  mutate(finns_m = str_detect(first_name, 'm'))
## A tibble: 3 × 4
  first_name last_name full_name      finns_m
  <chr>      <chr>     <chr>          <lgl>
1 Maria      Svensson  Maria Svensson FALSE
2 Mohammed   Ayman     Mohammed Ayman TRUE
3 Magnus     Bentzel   Magnus Bentzel FALSE

Mit den Funktionen string_ends() und string_starts() lässt sich feststellen, ob ein String mit einem bestimmten String beginnt oder endet. Wir prüfen, ob der String mit M beginnt und mit s endet. Dazu erstellen wir zwei neue Variablen, die dies anzeigen:

my_data %>%
  mutate(starts_M = str_starts(first_name, 'M'),
         ends_s = str_ends(first_name, 's'))
## A tibble: 3 × 5
  first_name last_name full_name      starts_M ends_s
  <chr>      <chr>     <chr>          <lgl>    <lgl>
1 Maria      Svensson  Maria Svensson TRUE     FALSE
2 Mohammed   Ayman     Mohammed Ayman TRUE     FALSE
3 Magnus     Bentzel   Magnus Bentzel TRUE     TRUE

8.1.9 Strings und Zeichen ersetzen

Mit der Funktion [str_replace()](https://stringr.tidyverse.org/reference/str_replace.html) ersetzen Sie einen String ganz oder teilweise. Nun ersetzen wir den Buchstaben M durch ein Sternchen (*):

my_data %>%
  mutate(new_first_name = str_replace(first_name, 'M', '*'))
## A tibble: 3 × 4
  first_name last_name full_name      new_first_name
  <chr>      <chr>     <chr>          <chr>
1 Maria      Svensson  Maria Svensson *aria
2 Mohammed   Ayman     Mohammed Ayman *ohammed
3 Magnus     Bentzel   Magnus Bentzel *agnus

Die Funktion [str_replace()](https://stringr.tidyverse.org/reference/str_replace.html) ersetzt nur die erste Instanz (das erste Vorkommen) des gesuchten Musters. Verwenden Sie die Funktion [str_replace_all()](https://stringr.tidyverse.org/reference/str_replace.html), um alle Instanzen zu ersetzen. Im Folgenden ersetzen wir alle m durch *:

my_data %>%
  mutate(new_first_name = str_replace_all(first_name, 'm', '*'))
## A tibble: 3 × 4
  first_name last_name full_name      new_first_name
  <chr>      <chr>     <chr>          <chr>
1 Maria      Svensson  Maria Svensson Maria
2 Mohammed   Ayman     Mohammed Ayman Moha**ed
3 Magnus     Bentzel   Magnus Bentzel Magnus

8.1.10 NA durch „NA“ ersetzen

Missing Data ist der englische Begriff für fehlende Informationen. Meist wird nur das Wort Missing verwendet, um fehlende Daten zu bezeichnen. Fehlende Werte werden in R mit NA (Not Available) gekennzeichnet. Wir können einen fehlenden Wert in einem Character-Vektor erzeugen, indem wir den Wert NA ohne Anführungszeichen angeben:

x <- c("abc", NA)
x
[1] "abc" NA

Beachten Sie, dass der String „abc“ von Anführungszeichen umgeben ist, um anzuzeigen, dass es sich um einen String handelt. NA ist dagegen nicht von Anführungszeichen umgeben, da es Missing ist. Wir können Missing (NA) durch den String NA (“NA") ersetzen.

x <- c("abc", NA)
str_replace_na(x)
[1] "abc" "NA"

8.1.11 Teile von Strings extrahieren (Substring)

Die Funktion [str_sub()](https://stringr.tidyverse.org/reference/str_sub.html) kann Teile von Strings extrahieren. Die Funktion hat die Argumente start und end, die angeben, wo die Extraktion beginnt und endet. Hier extrahieren wir die erste bis zweite Position:

x <- c("Sommarlov")
str_sub(string=x, start=1, end=2)
[1] "So"

Wie üblich können wir Werte für die Argumente string, start und end angeben, ohne die Namen der Argumente zu nennen, vorausgesetzt, wir geben die Werte in der richtigen Reihenfolge an:

x <- c("Sommarlov")
str_sub(x, 1, 2)
[1] "So"

Negative Werte für start und end bedeuten, dass die Extraktion am Ende des Strings beginnt. Hier extrahieren wir alle Zeichen vom vorletzten bis zum letzten:

x <- c("Sommarlov")
str_sub(x, -2, -1)
[1] "ov"

Wenn Sie versuchen, mehr zu extrahieren, als im String vorhanden ist, gibt [str_sub()](https://stringr.tidyverse.org/reference/str_sub.html) so viel wie möglich zurück:

x <- c("Sommarlov")
str_sub(x, 1, 100)
[1] "Sommarlov"

8.2 Reguläre Ausdrücke (Regex)

In der Praxis müssen Sie möglicherweise noch ausgefeiltere Treffer erzielen, und dann sind reguläre Ausdrücke unschätzbar wertvoll. Reguläre Ausdrücke (regular expressions, Regex) sind eine Zeichenfolge, die in einem String nach einem Muster sucht.

Weitere Ressourcen zu regulären Ausdrücken:

  • https://www.regular-expressions.info/ bietet ausführliche Informationen darüber, wie reguläre Ausdrücke funktionieren.
  • https://regex101.com ist ein interaktives Werkzeug, mit dem Sie Ihre regulären Ausdrücke live testen können, um zu sehen, ob sie sich wie erwartet verhalten.

Reguläre Ausdrücke mögen auf den ersten Blick kompliziert wirken, doch sobald Sie verstanden haben, wie sie funktionieren, werden Sie erkennen, dass sie äußerst leistungsfähig für die Arbeit mit Strings sind. Oft ist einiges Ausprobieren nötig, bis man einen funktionierenden regulären Ausdruck hat. Um zu sehen, wie Ihr regulärer Ausdruck die Zeichen in einem String trifft, gibt es die Funktionen [str_view()](https://stringr.tidyverse.org/reference/str_view.html) und [str_view_all()](https://stringr.tidyverse.org/reference/str_view.html). Diese zeigen, wie reguläre Ausdrücke auf einen String passen. Die Funktionen markieren den Teil des Strings, der zu Ihrem regulären Ausdruck passt. Wir verwenden die Funktion nun, um zu sehen, ob unser regulärer Ausdruck den Buchstaben X in den folgenden Strings findet. Der zu durchsuchende String wird im Argument string angegeben, das gesuchte Muster in pattern:

my_strings <- c("Xxx", "Yyy", "Xxx")
str_view(string=my_strings, pattern='X')
Ausgabe von str_view, in der das erste X in den Strings Xxx und Xxx markiert ist, in Yyy jedoch nichts

Der senkrechte Strich (|) bedeutet „oder“. Mit dem senkrechten Strich können wir nach verschiedenen Zeichen suchen, von denen nur eines passen muss. Im Folgenden geben wir pattern='X|x' an, das heißt, wir suchen nach X oder x.

my_strings <- c("Xxx", "xXx")
str_view(string=my_strings, pattern='X|x')
Ausgabe von str_view mit dem Muster X|x, in der in den Strings Xxx und xXx nur das erste Zeichen markiert ist

Wie oben zu sehen ist, wurde nur das erste X oder x getroffen, was daran liegt, dass wir [str_view()](https://stringr.tidyverse.org/reference/str_view.html) verwendet haben. Die Funktion [str_view_all()](https://stringr.tidyverse.org/reference/str_view.html) kann alle Vorkommen eines Strings treffen. Ein Beispiel folgt:

my_strings <- c("Xxx", "xXx")
str_view_all(string=my_strings, pattern='X|x')
Ausgabe von str_view_all mit dem Muster X|x, in der alle Zeichen in den Strings Xxx und xXx markiert sind

Mit den Funktionen [str_view()](https://stringr.tidyverse.org/reference/str_view.html) und [str_view_all()](https://stringr.tidyverse.org/reference/str_view.html) können Sie also sehen, wie ein regulärer Ausdruck (Regex) auf einen String passt. Hier folgt ein Beispiel, in dem wir mit [str_view()](https://stringr.tidyverse.org/reference/str_view.html) prüfen, ob unser regulärer Ausdruck H am Anfang eines Strings treffen kann. In regulären Ausdrücken wird ^ verwendet, um den Anfang eines Strings zu kennzeichnen. Um H am Anfang eines Strings zu treffen, schreibt man daher Folgendes:

str_view(string='Hej', pattern='^H')
Ausgabe von str_view, in der der Buchstabe H am Anfang des Strings Hej markiert ist

Es scheint, dass unser regulärer Ausdruck wie erwartet H trifft.

Der Punkt (.) ist ein regulärer Ausdruck, der ein beliebiges Zeichen trifft. Im Folgenden testen wir, ob wir A. in einem von mehreren Strings eines Vektors treffen können:

my_strings <- c("A", "AB", "ABC")
str_view(my_strings, 'A.')
Ausgabe von str_view mit dem Muster A., in der AB in AB und ABC markiert ist, während der String A keinen Treffer hat

Der erste String A wird nicht getroffen, da auf A kein weiteres Zeichen folgt. Die Strings AB und ABC werden getroffen, da sie ein A gefolgt von einem weiteren Zeichen enthalten.

Im nächsten Beispiel haben wir den String X.X, den wir exakt treffen möchten. Der Punkt soll nicht als Sonderzeichen behandelt, sondern exakt getroffen werden. Wäre es nur ein String gewesen, hätten wir X\.X verwenden können. Da wir aber einen regulären Ausdruck zum Abgleich verwenden möchten, müssen wir einen weiteren Backslash \ hinzufügen, weil auch Regex dieses Symbol als Escape-Symbol verwendet. Daher ist folgender Code nötig, um X.X exakt zu treffen:

Wenn Sie stattdessen exakt „A.C“ treffen möchten, muss ein Escape (\) wie folgt verwendet werden:

my_strings <- c("X.X")
str_view(my_strings, "X\\.X")
Ausgabe von str_view, in der der gesamte String X.X als exakter Treffer markiert ist

Wie trifft man \ in einem String mit einem regulären Ausdruck? Zunächst muss \ als gewöhnliches Zeichen (ohne besondere Funktion) interpretiert werden, was einen weiteren \ erfordert. Wir schreiben zunächst einen Vornamen und einen Nachnamen, getrennt durch \\. Dies sollte einen \ ergeben, wenn wir es mit [writeLines()](https://rdrr.io/r/base/writeLines.html) ausgeben:

my_string <- "Monika \\ Svensson"
writeLines(my_string)
Monika \ Svensson

Wir brauchen also zwei Backslashes (\\), um einen String mit einem Backslash zu erhalten. Für einen regulären Ausdruck wird nun pro Backslash ein weiterer Backslash benötigt. Um einen Backslash in einem String zu treffen, ist also folgender Code nötig:

str_view(my_string, "\\\\")
Ausgabe von str_view, in der der Backslash zwischen dem Vornamen Monika und dem Nachnamen Svensson markiert ist

Da reguläre Ausdrücke und Strings dasselbe Escape-Symbol (\) verwenden, sind also doppelte Escapes nötig, wenn Sie reguläre Ausdrücke für bestimmte Zeichen und Symbole verwenden. Es ist möglich, das Escape für das Zeichen selbst zu vermeiden und nur das Escape für den regulären Ausdruck anzugeben, indem man [raw()](https://rdrr.io/r/base/raw.html) verwendet. Dies steht für raw vectors,

str_view(my_string, r"(\\)")
Ausgabe von str_view, in der der Backslash zwischen dem Vornamen Monika und dem Nachnamen Svensson markiert ist

Um ein Sternchen (*) zu treffen, gilt dasselbe Prinzip:

str_view(string=c("abc", "a.c", "a*c", "a c"), pattern="\\*")
Ausgabe von str_view, in der das Sternchen in a*c markiert ist, während abc, a.c und a c keinen Treffer haben

Es gibt weitere reguläre Ausdrücke für Treffer in Strings, und diese lassen sich kombinieren. Sie lauten wie folgt:

Sequence Matches
. Any character except newline
[xyz] Any character listed between the brackets (x, y, and z in this example)
[a-z] Any character between a and z, inclusive
[^xyz] The opposite of [xyz]
\d ASCII digits (0 through 9, inclusive)
\D Anything except ASCII digits
\s ASCII spaces (space, tab, newline, carriage return, form feed)
\S Anything except ASCII spaces
\w The same as [0-9A-Za-z_]
\W Anything except the characters matched by \w
[[:alnum:]] The same as [0-9A-Za-z]
[[:alpha:]] The same as [A-Za-z]
[[:ascii:]] Any ASCII character
[[:blank:]] ASCII tab or space
[[:cntrl:]] ASCII/Unicode control characters
[[:digit:]] The same as [0-9]
[[:graph:]] All “graphical” (printable) ASCII characters
[[:lower:]] The same as [a-z]
[[:print:]] The same as [[:graph:]]
[[:punct:]] The same as [!-/:-@[-`{-~]
[[:space:]] The same as [\t\n\v\f\r ]
[[:upper:]] The same as [A-Z]
[[:word:]] The same as \w
[[:xdigit:]] The same as [0-9A-Fa-f]
\pN Unicode character class by using single-letter class names (“N” in this example)
\p{Greek} Unicode character class by unicode name (“Greek” in this example)
\PN The opposite of \pN
\P{Greek} The opposite of \p{Greek}
xy x followed immediately by y
x|y either x or y, preferring x
x* zero or more x, preferring more
x*? zero or more x, preferring fewer
x+ one or more x, preferring more
x+? one or more x, preferring fewer
x? zero or one x, preferring one
x?? zero or one x, preferring zero
x{n,m} between n and m repetitions of x, preferring more
x{n,m}? between n and m repetitions of x, preferring fewer
x{n,} at least n repetitions of x, preferring more
x{n,}? at least n repetitions of x, preferring fewer
x{n} exactly n repetitions of x
(x) unnamed capture group for sub-pattern x
(?P<name>x) named capture group, named name, for sub-pattern x
(?:x) non-capturing sub-pattern x
\* Literal * for any punctuation character *
\Q...\E Literal ... for any text ... as long as it does not include literally \E

8.3 Anker (^, $)

Es gibt auch reguläre Ausdrücke, die angeben, wo Treffer erfolgen sollen. Die gebräuchlichsten Symbole sind ^, das angibt, dass der Treffer am Anfang eines Strings erfolgen soll, und $, das angibt, dass der Treffer am Ende des Strings erfolgen soll.

Sequence Matches
^ At the beginning of the given string
$ At the end of the given string
\A At the beginning of the given string
\z At the end of the given string
\b At an ASCII word boundary (transition between \w and either \W, \A or \z, or vice-versa)
\B Not at an ASCII word boundary

8.3.1 Character Set (Zeichenklasse)

Ein character set ist eine Liste von Zeichen, die getroffen werden sollen. Die Liste wird in [] angegeben. Um die Buchstaben a, b oder c zu treffen, wird folgendes Character Set verwendet: [abc]. Ein Character Set ist vorteilhaft, weil man für die Symbole regulärer Ausdrücke kein Escape (\) angeben muss. Für folgende Symbole benötigen Sie kein Escape: $ . | ? * + ( ) [ {. Das bedeutet, dass Sie diese Symbole im Character Set direkt schreiben und treffen können (ohne Escape anzugeben). Um ., , a b oder c zu treffen, wird folgendes Character Set verwendet: [.*abc]

Es gibt jedoch Symbole, die auch innerhalb eines Character Sets eine besondere Funktion haben, und zwar folgende:

  • ]
  • ^ negiert die Liste.
    • [^abc] trifft alles außer a, b und c.
    • [a-zA-Z0-9] trifft alle Kleinbuchstaben, Großbuchstaben und Ziffern
  • - definiert einen Bereich, der der alphabetischen oder numerischen Reihenfolge folgt.
    • Beispiel: [a-d] trifft die Buchstaben a, b, c oder d.
    • Beispiel: [0-4] trifft die Ziffern 0, 1, 2, 3, 4
  • \ wird verwendet, um ], ^ und - in einem Character Set zu escapen.
    • [a\\-c] trifft a-c.
    • [\^\-] trifft ^-.

Nun werden Strings getroffen, die mit a beginnen und mit b enden und dazwischen entweder ein Sternchen (*) oder den Buchstaben b haben:

str_view(c("abc", "a.c", "a*c", "a c"), "a[*b]c")
Ausgabe von str_view mit dem Muster a[*b]c, in der abc und a*c markiert sind, während a.c und a c keinen Treffer haben

Beachten Sie, dass wir das Sternchen (*) treffen konnten, ohne \\ zu verwenden, was sich dadurch erklärt, dass wir stattdessen [] verwendet haben, was als Character Class bezeichnet wird. Versuchen wir es noch einmal, ersetzen aber nun das erste a durch ein beliebiges Zeichen (.):

str_view(c("abc", "a.c", "a*c", "a c"), ".[*]c")
Ausgabe von str_view mit dem Muster .[*]c, in der unter vier Strings nur a*c markiert ist

Um ein Leerzeichen zu treffen, kann man ein gewöhnliches Leerzeichen verwenden, mit oder ohne Zeichenklasse:

str_view(string=c("a c", "a.c", "a*c"), pattern="a[ ]c")
Ausgabe von str_view, in der der String a c mit Leerzeichen markiert ist, während a.c und a*c keinen Treffer haben
str_view(string=c("a c", "a.c", "a*c"), pattern="a c")
Ausgabe von str_view, in der der String a c mit Leerzeichen markiert ist, während a.c und a*c keinen Treffer haben

8.3.2 Alternierende Treffer

Sie können mehrere Alternativen treffen, indem Sie den senkrechten Strich (|) wie folgt verwenden:

str_view(c("a", "b", "c", "d"), "a|b")
Ausgabe von str_view mit dem Muster a|b, in der die Buchstaben a und b markiert sind, c und d jedoch nicht

Sie können mehr als zwei Alternativen treffen:

str_view(c("a", "b", "c", "d"), "a|b|c")
Ausgabe von str_view mit dem Muster a|b|c, in der a, b und c markiert sind, d jedoch nicht

Wenn Sie innerhalb eines Wortes treffen, sind Klammern nötig, wie folgt:

str_view(c("glad", "glöd"), "gl(a|ö)d")
Ausgabe von str_view, in der sowohl glad als auch glöd als Treffer für das Muster gl(a|ö)d markiert sind
my_words <- c("Sommarlov", "Okidoki", "Tackar", "Bolag")

## Beginnt das Wort mit dem Buchstaben S?
str_detect(my_words, "^S")
[1]  TRUE FALSE FALSE FALSE
## Wie viele Wörter enden auf den Buchstaben i oder r?
str_detect(my_words, "[ir]$")
[1] FALSE  TRUE  TRUE FALSE
str_subset(my_words, "x$")
character(0)

8.3.3 Treffer negieren

Statt alle Strings zu finden, die ein bestimmtes Symbol enthalten, können wir den Treffer negieren. Dies lässt sich durch ein Ausrufezeichen (!) vor [str_detect()](https://stringr.tidyverse.org/reference/str_detect.html) erreichen. Das Ausrufezeichen (!) bedeutet „umgekehrt“ oder „nicht“. Das heißt, !str_detect() bedeutet, dass ein String nicht getroffen werden kann. Probieren wir es aus:

## Welche Wörter beginnen nicht mit S?
my_words <- c("Sommarlov", "Okidoki", "Tackar", "Bolag")
!str_detect(my_words, "^S")
[1] FALSE  TRUE  TRUE  TRUE

Sie können einen Treffer auch mithilfe einer Zeichenklasse negieren. Dazu beginnt man die Zeichenklasse mit ^ . Mit folgendem Code werden Wörter ermittelt, die nicht mit S beginnen:

## Welche Wörter beginnen nicht mit S?
my_words <- c("Sommarlov", "Okidoki", "Tackar", "Bolag")
str_detect(my_words, "^[^S]")
[1] FALSE  TRUE  TRUE  TRUE

8.4 Wiederholte Treffer

Mit folgenden Zeichen können wir steuern, wie oft ein String getroffen werden kann:

  • ?: 0 oder 1 Mal
  • +: Mindestens 1 Mal
  • *: Mindestens 0 Mal
my_string <- "AAAAAA"

str_view(my_string, "AA?")
Ausgabe von str_view, in der die ersten beiden A im String AAAAAA markiert sind
str_view(my_string, "AA+")
Ausgabe von str_view, in der der gesamte String AAAAAA als ein Treffer markiert ist
str_view(my_string, "AA*")
Ausgabe von str_view, in der der gesamte String AAAAAA als ein Treffer markiert ist

Mit geschweiften Klammern können Sie angeben, wie oft ein Treffer erfolgen soll:

  • {n}: n Mal
  • {n,}: n Mal oder öfter
  • {,m}: höchstens m Mal
  • {n,m}: zwischen n und m Mal
str_view(my_string, "A{2}")
Ausgabe von str_view, in der die ersten beiden A im String AAAAAA markiert sind
str_view(my_string, "A{2,}")
Ausgabe von str_view für mindestens zwei A, in der der gesamte String AAAAAA markiert ist
str_view(my_string, "A{2,3}")
Ausgabe von str_view für zwei bis drei A, in der die ersten drei A in AAAAAA markiert sind

8.4.1 Shorthand Character Classes

Es gibt Character Sets, die abgekürzt wurden, weil sie so häufig verwendet werden. Diese lauten wie folgt:

  • \d: trifft jede beliebige Ziffer \D: trifft alles, was keine Ziffer ist
  • \s: trifft alle Leerräume (z. B. Leerzeichen, Tab, Zeilenumbruch); \S: trifft alles, was kein Leerraum ist
  • \w: trifft alle Ziffern und Buchstaben \W: trifft alles, was keine Ziffer und kein Buchstabe ist

In regulären Ausdrücken müssen sie mit einem zusätzlichen Backslash angegeben werden. Für \d ergibt sich somit \\d.

Treffen wir alle Ziffern bzw. alles, was keine Ziffer ist:

str_view_all("Hej! 123456 @ # %", "\\d")
Ausgabe von str_view_all, in der jede Ziffer von 1 bis 6 im String Hej! 123456 @ # % markiert ist
str_view_all("Hej! 123456 @ # %", "\\D")
Ausgabe von str_view_all, in der alle Zeichen außer den Ziffern im String Hej! 123456 @ # % markiert sind

Alle Buchstaben und Ziffern treffen bzw. das Gegenteil.

str_view_all("Hej! 123456 @ # %", "\\w")
Ausgabe von str_view_all, in der die Buchstaben in Hej und die Ziffern 1 bis 6 markiert sind, Satzzeichen und Symbole jedoch nicht
str_view_all("Hej! 123456 @ # %", "\\W")
Ausgabe von str_view_all, in der Ausrufezeichen, Leerzeichen und die Symbole @ # % markiert sind, Buchstaben und Ziffern jedoch nicht

Alle Leerräume treffen bzw. das Gegenteil.

str_view_all("Hej! 123456 @ # %", "\\s")
Ausgabe von str_view_all, in der die vier Leerzeichen im String Hej! 123456 @ # % markiert sind
str_view_all("Hej! 123456 @ # %", "\\S")
Ausgabe von str_view_all, in der alle Zeichen außer den Leerzeichen im String Hej! 123456 @ # % markiert sind

Alle Sequenzen aus 5 Buchstaben oder Ziffern oder aus 2 Ziffern treffen:

str_view_all("Hej jag heter Maggi och har telefonnummer 123456", "\\w{5}|\\d{2}")
Ausgabe von str_view_all, in der Sequenzen aus fünf Wortzeichen in einem Satz markiert sind, unter anderem heter, Maggi und 12345

8.4.2 Rangfolge der Operatoren

Bei mathematischen Berechnungen gibt es eine Rangfolge der Operanden. Multiplikation geht vor Addition und Subtraktion. Die Berechnung 1*2+3 wird als (1*2)+3 berechnet, weil die Multiplikation Vorrang hat. Auch für reguläre Ausdrücke gibt es Rangfolgen. Quantifizierer (zum Beispiel +) haben einen höheren Vorrang als Alternationen (|). Liefert ein regulärer Ausdruck ein unerwartetes Ergebnis, muss die Rangfolge möglicherweise mit Klammern verdeutlicht werden. Ein Beispiel folgt:

## Weniger eindeutiger regulärer Ausdruck
str_view("Jag hittade en vattenkanna", "an+")
Ausgabe von str_view, in der die Teilzeichenkette ann im Wort vattenkanna markiert ist
## Eindeutigerer regulärer Ausdruck
str_view("Jag hittade en vattenkanna", "a(n+)")
Ausgabe von str_view, in der die Teilzeichenkette ann im Wort vattenkanna markiert ist

8.4.3 Boolesche Treffer und Bedingungen

Sie können den senkrechten Strich und & wie gewohnt auch bei Strings verwenden. Das bedeutet, dass diese beiden Befehle gleichwertig sind:

## Einen Vektor mit Wörtern erstellen
my_words <- c("hej", "bra", "ja", "kanske", "lite", "mycket", "troligen", "sannolikt", "utmärkt")

## Alle Wörter ermitteln, die "a" oder "b" enthalten
my_words[str_detect(my_words, "a") | str_detect(my_words, "b")]
[1] "bra"       "ja"        "kanske"    "sannolikt"
## Alle Wörter ermitteln, die "a" oder "b" enthalten
my_words[str_detect(my_words, "a|b")]
[1] "bra"       "ja"        "kanske"    "sannolikt"

Auf ähnliche Weise können Sie weitere nützliche Bedingungen formulieren:

## Alle Wörter ermitteln, die "a" und "n" und "k" enthalten
my_words[str_detect(my_words, "a") & str_detect(my_words, "n") & str_detect(my_words, "k")]
[1] "kanske"    "sannolikt"