--- title: "RegExp-Kurs - R (stringr)" author: "tegula" date: '2022-07-05' output: html_document --- ```{r setup, include=FALSE} knitr::opts_chunk$set(echo = TRUE) ``` [Kursübersicht](https://debianforum.de/forum/viewtopic.php?t=183941) # Einleitung In diesem Thread geht es um die Anwendung von regulären Ausdrücken in R mittels des Packages (der Bibliothek) stringr. > : "R ist eine freie Programmiersprache für statistische Berechnungen und Grafiken. Sie wurde 1992 von Statistikern für Anwender mit statistischen Aufgaben neu entwickelt. Die Syntax orientiert sich an der Programmiersprache S, mit der R weitgehend kompatibel ist, und die Semantik an Scheme. Als Standarddistribution wird R mit einem Interpreter als Kommandozeilenumgebung mit reduzierten grafischen Schaltflächen angeboten. So ist R aktuell auf den wichtigsten Plattformen verfügbar; die Umgebung wird von den Entwicklern ausdrücklich ebenfalls als R bezeichnet. R ist Teil des GNU-Projekts". Bei Stringr handelt es sich um einen benutzerfreundliche Oberfläche/Wrapper für die stringi-Bibliothek. Der verwendete Regex-Dialekt wird "ICU" oder "Java-ähnlich" bezeichnet (). Die ERE-Ausdrücke, die wir während des Grundlagen-Kurses von Meillo gelernt haben, können (nach Anpassung der Escapezeichen; siehe weiter unten) in der Regel übernommen werden. # Installation R und die für den Kursteil benötigten R-Packages sind in offiziellen Debian-Quellen verfügbar. r-recommendedund r-cran-tidyverse werden benötigt. Optional: Für diesen Kurs-Part reicht prinzipiell ein beliebiger Texteditor. Eine integrierte Entwicklungsumgebung macht die Benutzung von R aber bequemer und einfacher. Eine Übersicht findet sich im Archwiki () oder auf Wikipedia . # Besondersheiten von R ## Zuweisungsoperator Im Unterschied zu Python, gibt es in R zwei Möglichkeiten eine Zuweisung auszudrücken. "<-" und "=". Für die Zuweisung eines Wertes an ein Objekt sind beide Schreibweisen möglich. Für die Übergabe eines Schlüsselwortarguments an eine Funktionen oder eine Methode ist hingegen (wie in Python) ausschließlich die Schreibweise "=" erlaubt. ```{r} library(magrittr) data(trees) # Zuweisung an Objekte: Sowohl "<-" als auch "=" sind erlaubt. volumen_kubikzoll = trees$Volume volumen_kubikzoll <- trees$Volume summary(object = volumen_kubikzoll, digit = 4) ``` ## Pipe-Operator Im weiteren Verlauf dieser Einführung wird häufig der Pipe-Operator %>% verwendet. Der Pipe-Operator ermöglicht es zwei Funktionen miteinander zu verknüpfen. Das heißt die zweite Funktion verwendet den Rückgabewert der ersten Funktion als (ootb: erstes positionales) Argument. Der Pipe-Operator stellt damit eine IMHO flexiblere und übersichtlichere Alternative zu Klammern da. Um den Pipe-Operator verwenden zu können, ist es allerdings erforderlich, zuvor entweder das Package magrittr oder Meta-Package tidyverse zu laden. ```{r} library(magrittr) data(mtcars) # Beispieldatensatz (ist in R enthalten) laden # Folgendes wird gemacht: Die Antriebsleistung der Autos wird von Pferdestärken (Pferdestärken) in Kilowatt (kW) umgerechnet. Anschließen werden das (als Zahl vorliegende) Ergebnis in eine Zeichenkette umwandelt. Zum Schluss wird die Angabe der Einheit ("kW") zu dieser Zeichenkette hinzufügt. ## Variante 1: Mit Klammern (ohne Pipe-Operator) --> IMHO eher unübersichtlich paste((as.character(multiply_by(mtcars$hp, 0.746))), "kW", sep = " ") ## Variante 2: Mit Pipe-Operator (in einer Zeile) --> IMHO schon übersichtlicher mtcars$hp %>% multiply_by(0.746) %>% as.character %>% paste("kW", sep = " ") ## Variante 3: Mit Pipe-Operator (in mehren Zeilen --> IMHO noch mal übersichtlicher mtcars$hp %>% multiply_by(0.746) %>% as.character %>% paste("kW", sep = " ") ``` Weitergehende Infos (für Kurs-Part nicht nötig): ## Escaping Als Escapezeichen dient der Backslash. Eine Besonderheit innerhalb R ist jedoch, dass grundsätzlich doppelt escapet werden muss, um aus einen Standardzeichen ein Metazeichen zu machen. _De facto_ dient also ein doppelter Backslash als Escape-Zeichen. ```{r} library(tidyverse) # TODO: Es soll nur die Schreibweise mit zwei getrennten Wörter ("hallo debianforum") gefunden werden. ## richtig: "hallo_debianforum hallo debianforum" %>% str_extract_all(pattern = "hallo\\b.debianforum") ## falsch: "hallo_debianforum hallo debianforum" %>% str_extract_all(pattern = "hallo\b.debianforum") ``` Weitergehende Infos: (Seite 2, linke Spalte "Need to Know"). # Übersicht über die in stringr möglichen regulären Ausdrucke Ein tabellarische Übersicht der innerhalb von stringr zur Verfügung stehenden Operationen und Zeichenklassen bietet die zweite Seite des Cheat-Sheets "strings" von Rstudio: . Eine Übersicht als Fließtext liefert die die Vignette "regular expressions": . # Funktion im stringr-Package Die Überblick über die in stringr enthaltenen regex-Funktionen ist zum Beispiel in der Vignette "Introduction to stringr" zu finden: zu finden. Eine ausführliche Beschreibung findet sich in der Befehlsreferenz des stringr-Packages: . # Vorbereitung ## Arbeitsverzeichnis festlegen, Script-Datei erstellen und Schwäbische Kunde downloaden: Erstellt ein Verzeichnis (z. B. ~/regex_R) für diesen Kurs-Part und speichert dort eine leere Textdatei mit der Dateinamensendung ".R" (z. B. skript_regex.R) sowie die Schwäbische_Kunde (). Öffnet das Script und fügt folgenden Befehl ein, um das Arbeitsverzeichnis festzulegen. ```{r eval=FALSE} #!/usr/bin/env Rscript #optional setwd(~/regex_R) # Arbeitsverzeichnis festlegen (Pfad ggf. anpassen) getwd() # Arbeitsverzeichnis anzeigen print("Das ist ein Test") # Zeichenkette "Das ist ein Test" ausgeben ``` ## Skript ausführen (Ohne Entwicklungsumgebung): (Wenn ihr eine Entwicklungsumgebung zum Ausführen des Befehle bzw. eures Skripts nutzt, könnt ihr diesen Abschnitt überspringen.) Öffnet ein Terminal, wechselt in eurer Arbeitsverzeichnis und übergebt das Script an das Programm Rscript. Daraufhin wird das Skript ausgeführt. ```{bash eval=FALSE} cd ~/regex_R # Pfad zum Arbeitsverzeichnis ggf. anpassen Rscript skript_regex.R # Pfad ggf. anpassen ``` ## Schwäbische Kunde importieren und für spätere Verwendung abspeichern. Zum importieren der Schwäbischen Kunde benutzen wir die Funktion read_lines aus dem Package readr. Das Ergebnis des Imports speichern wir unter dem Dateinamen "schwaebische_kunde.RData" ab, um es später wiederverwenden zu können. ```{r} # Importieren schwaebische_kunde <- readr::read_lines("schwaebische-kunde.txt") %>% dplyr::as_tibble() %>% dplyr::rename(text = value) %>% tibble::rowid_to_column("zeile") # abspeichern save(schwaebische_kunde, file = "schwaebische_kunde.RData") ``` # Funktion im stringr-Package Ein Überblick über die in stringr enthaltenen regex-Funktionen ist zum Beispiel in der Vignette "Introduction to stringr" zu finden: zu finden. Eine ausführliche Beschreibung findet sich in der Befehlreferenz des stringr-Packages: . ## Feststellen, ob ein Match vorliegt: str_detect ```{r} # Tidyverse laden library(tidyverse) # Schwäbische Kunde laden load("schwaebische_kunde.RData") # Regex-Funktion ausführen: ## Zeile enthält einen Punkt schwaebische_kunde$is_match <- schwaebische_kunde$text %>% str_detect(pattern = "[:punct:]") # Ergebnis ausgeben schwaebische_kunde %>% print(n = Inf) ``` ## Feststellen eines Matches am Beginn bzw. Ende einer Zeichenfolge: str_starts und str_ends Soll nur der Beginn bzw. Ende einer Zeichenfolge betrachtet werden, so bietet sich die Nutzung der Funktionen str_starts bzw. str_ends an. Die Angabe der Zeilenanker ^ und $ kann bei der Verwendung dieser Funktionen entfallen. ```{r} input_string <- "debianforum.de" # Match am Anfang einer Zeichenfolge feststellen input_string %>% str_starts(pattern = "[dD]") # entspricht ... input_string %>% str_detect(pattern = "^[dD]") # Match am Ende einer Zeichenfolge feststellen input_string %>% str_ends(pattern = "de") input_string %>% str_detect(pattern = "de") ``` ## Anzahl der Matches bestimmen: str_count ```{r} # Tidyverse laden library(tidyverse) # Schwäbische Kunde laden load("schwaebische_kunde.RData") # Regex-Funktion ausführen ## Wörter je Zeichenfolge (entspricht hier: Wörter je Strophe) schwaebische_kunde$n_matches <- schwaebische_kunde$text %>% str_count(pattern = "\\b[:alpha:]") # Ergebnis anzeigen schwaebische_kunde %>% print(n = Inf) ``` ## Position des _ersten_ Matches bestimmen: str_locate ```{r} # Tidyverse laden library(tidyverse) # Schwäbische Kunde laden load("schwaebische_kunde.RData") # Regex-Funktion ausführen ## erstes auftreten des Buchstaben A bzw. a schwaebische_kunde$position <- schwaebische_kunde$text %>% str_locate(pattern = "[aA]") # Ergebnis anzeigen schwaebische_kunde %>% print (n = Inf) ``` ## Position _aller_ matches bestimmen: str_locate_all ```{r} # Tidyverse laden library(tidyverse) # Schwäbische Kunde laden load("schwaebische_kunde.RData") # Regex-Funktion ausführen ## jedes auftreten von A bzw. a str_locate_all(string = schwaebische_kunde$text, pattern = "[Aa]") ``` ## _erstes_ Match extrahieren: ```{r} # Tidyverse laden library(tidyverse) # Schwäbische Kunde laden load("schwaebische_kunde.RData") # Regex-Funktion ausführen ## Der auf "schwäb" oder "schwab" folgende schwaebische_kunde$first_match <- schwaebische_kunde$text %>% str_match(pattern = "[aA]") # Ergebnis anzeigen schwaebische_kunde %>% print (n = Inf) ``` ## _alle_ Matches extrahieren: str_extract_all ```{r} # Tidyverse laden library(tidyverse) # Schwäbische Kunde laden load("schwaebische_kunde.RData") # Regex-Funktion ausführen ## jedes auftreten von A bzw. a schwaebische_kunde$text %>% str_extract_all(pattern = "[aA]") # Ergebnis anzeigen schwaebische_kunde %>% print (n = Inf) ``` ## Gruppen extrahieren (nur erstes match): str_match ```{r} # Tidyverse laden library(tidyverse) # Schwäbische Kunde laden load("schwaebische_kunde.RData") # Regex-Funktion ausführen ## Extrahiere das Wort vor dem ersten Komma oder Punkt schwaebische_kunde$first_match_group <- schwaebische_kunde$text %>% str_match(pattern = "([:alnum:]*)[:blank:]*[.,].*") # Ergebnis anzeigen schwaebische_kunde %>% print (n = Inf) ``` ## Gruppen extrahieren (alle matches): str_match_all ```{r} # Tidyverse laden library(tidyverse) # Schwäbische Kunde laden load("schwaebische_kunde.RData") # Regex-Funktion ausführen ## Extrahiere alle Lleinbuchstaben, die auf einen Großbuchstaben folgen schwaebische_kunde$text %>% str_match_all("[:upper:]([:lower:])") ``` ## (Komplette) Zeichenkette zurückgeben, wenn mindestens ein Match enthalten ist: str_subset ```{r} # Tidyverse laden library(tidyverse) # Schwäbische Kunde laden load("schwaebische_kunde.RData") # Regex-Funktion ausführen: ## Zeichenfolgen (Zeilen), die ein Komma enthalten schwaebische_kunde$text %>% str_subset(pattern = ",") ``` ## Ersetzen (nur erstes Match ersetzen): str_replace ```{r} # Tidyverse laden library(tidyverse) # Schwäbische Kunde laden load("schwaebische_kunde.RData") # Regex-Funktion ausführen: ## Ersetze das erste Auftreten von "ae" durch "ä" schwaebische_kunde$text <- schwaebische_kunde$text %>% str_replace(pattern = "ae", replacement = "ä") # Ergebnis ausgeben schwaebische_kunde %>% print(n = Inf) ``` ## Ersetzten (alle Matches ersetzen): str_replace_all ```{r} # Tidyverse laden library(tidyverse) # Schwäbische Kunde laden load("schwaebische_kunde.RData") # Regex-Funktion ausführen: ## Ersetze alle Leerzeichen durch Unterstriche schwaebische_kunde$text <- schwaebische_kunde$text %>% str_replace_all(pattern = "[:space:]", replacement = "_") # Ergebnis anzeigen schwaebische_kunde %>% print(n = Inf) ``` # Aufgaben 1. Bestimme, wie viele Buchstaben, die URL des dfde-Unterforums "Softwareentwicklung und -paketierung, Scripting" () enthält. Zähle einmal mit und einmal ohne die Angabe des Protokolls ("https"). 2. Bestimme wie viele Verse (Zeilen) der Schwäbischen Kunde mit einem Vokal (Selbstlaut) beginnen. 3. Mehrere Einwohner von Neu New York wurden nach ihrer Lieblingsfarbe gefragt. Das Ergebnis findest du im NoPaste: . Ordne ihren Antworten mit Hilfe regulärer Ausdrücke den folgenden Kategorien zu "Rot", "Blau", "Grün", "Andere Farbe" und NA (fehlender Wert). 4.) Extrahiere aus der Schwäbischen Kunde alle Großbuchstaben. Formatiere die Ausgabe so, dass gentrennt nach Verse (Zeilen) folgende Informationen möglich übersichtlich angezeigt werden: 1.) Zeilenummer des Verses. 2.) Gesamter Text des Verses. 3.) Alle Großbuchstaben, die in diesem Verses enthalten sind. Du bist frei in der Wahl des Ausgabemediums (z. B. R-Konsole, Standardausgabe, Spreadsheet-Datei oder ähnliches). 5.) Denke Dir selbst eine Aufgabe für die anderen Teilnehmer dieses Kursteils aus. 6.) Löse die Aufgaben der anderen Teilnehmer. Bitte postet Eure Lösungen zu den Aufgaben 1-5 _frühestens_ ab Mittwoch (13. Juli). Bitte denkt als Aufgabenersteller bei Aufgabe 6 daran, anzugeben, ab wann Lösungen zu Eurer Aufgabe frühestens gepostet werden sollen :).