In diesem Thread geht es um die Anwendung von regulären Ausdrücken in R mittels des Packages (der Bibliothek) stringr.
https://de.wikipedia.org/wiki/R_(Programmiersprache) hat geschrieben: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.
Stringr stellt eine benutzerfreundliche Möglichkeit dar, reguläre Ausdrücke innerhalb von R zu verwenden. Der hierbei genutzte RE-Dialekt nennt sich "ICU" oder "Java-ähnlich". ERE-Ausdrücke, die wir während des Grundlagen-Kurses von Meillo gelernt haben, können (nach Anpassung der Escapezeichen (vgl. Kapitel 2, Unterabschnitt "Escaping") und der vordefinierten Zeichenklasse (vgl. Kapitel 4)) in der Regel ohne Probleme übernommen werden .https://stringr.tidyverse.org/ hat geschrieben: The stringr package provide[s] a cohesive set of functions designed to make working with strings as easy as possible. [...] stringr is built on top of stringi, which uses the ICU C library to provide fast, correct implementations of common string manipulations. stringr focusses on the most important and commonly used string manipulation functions whereas stringi provides a comprehensive set covering almost anything you can imagine.
1.) Installation
R und die für den Kursteil benötigten R-Packages sind in den offiziellen Debian-Quellen verfügbar. Benötigt werden r-recommended und r-cran-tidyverse.
Optional: Für diesen Kurs-Part ist ein beliebiger Texteditor ausreichend. Eine integrierte Entwicklungsumgebung macht die Benutzung von R aber bequemer und einfacher. Eine Übersicht findet sich im Archwiki (https://wiki.archlinux.org/title/R#Edit ... _R_support) oder auf Wikipedia (https://en.wikipedia.org/wiki/R_(progra ... Interfaces).
2.) Hilfreiches Vorwissen
Wenn ihr schon einmal R genutzt habt, könnt ihr diesen Abschnitt überspringen.
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 Funktion oder eine Methode ist hingegen (wie in Python) ausschließlich die Schreibweise "=" erlaubt.
Code: Alles auswählen
data(trees)
# Zuweisung von Werten an Objekte: Sowohl "<-" als auch "=" sind erlaubt.
volumen_kubikzoll = trees$Volume
volumen_kubikzoll <- trees$Volume
# Übergabe von Schlüsselwortargumenten an Funktionen: Ausschließlich "=" ist erlaubt.
summary(object = volumen_kubikzoll, digit = 4)
Code: Alles auswählen
library(magrittr)
data(mtcars)
# 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 = " ")
Escaping: Als Escapezeichen dient der Backslash. Eine Besonderheit 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.
Code: Alles auswählen
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")
3.) 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 (41651). Öffnet nun das R-Skript und fügt folgenden Befehl ein, um das Arbeitsverzeichnis festzulegen.
Code: Alles auswählen
#!/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 (statt Texteditor und Terminal) zum Ausführen der Befehle bzw. eures Skripts nutzt und/oder schon einmal R benutzt habt, könnt ihr diesen Unterabschnitt überspringen.)
Öffnet ein Terminal, wechselt in eurer Arbeitsverzeichnis und übergebt das Script an das Programm Rscript. Daraufhin wird das Skript ausgeführt.
Code: Alles auswählen
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.
Code: Alles auswählen
# 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")
Eine tabellarische Übersicht der innerhalb von stringr zur Verfügung stehenden Operationen und Zeichenklassen bietet die zweite Seite des Cheat-Sheets "strings" von Rstudio: https://github.com/rstudio/cheatsheets/ ... trings.pdf. Eine Übersicht als Fließtext liefert die Vignette "regular expressions": https://cloud.r-project.org/web/package ... sions.html. Ein auffälliger Unterschied zu egrep (ERE) besteht darin, dass auch vordefinierte Zeichenklassen nur in einfache (statt doppelte) eckige Klammern gesetzt werden.
Code: Alles auswählen
library(tidyverse)
# Nur Elemente der vordefinierten Zeichenklasse "[:digit:]" (Zahlen) extrahieren
"Die folgende Zahl lautet 9 (in Worten: Neun)." %>%
str_extract_all(pattern = "[:digit:]")
Ein Überblick über die in stringr enthaltenen regex-Funktionen ist zum Beispiel in der Vignette "Introduction to stringr" zu finden: https://stringr.tidyverse.org/articles ... n-matching zu finden. Eine ausführliche Beschreibung findet sich in der Befehlreferenz des stringr-Packages: https://cloud.r-project.org/web/package ... tringr.pdf.
Feststellen, ob ein Match vorliegt: str_detect
Code: Alles auswählen
# Tidyverse laden
library(tidyverse)
# Schwäbische Kunde laden
load("schwaebische_kunde.RData")
# Regex-Funktion ausführen:
## Zeile soll ein Komma enthalten.
schwaebische_kunde$is_match <- schwaebische_kunde$text %>%
str_detect(pattern = ",")
# 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.
Code: Alles auswählen
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") # entspricht ...
input_string %>% str_detect(pattern = "de$")
Anzahl der Matches bestimmen: str_count
Code: Alles auswählen
# Tidyverse laden
library(tidyverse)
# Schwäbische Kunde laden
load("schwaebische_kunde.RData")
# Regex-Funktion ausführen
## Vorkommen des Buchstabens e bzw. E in der jeweiligen Zeichenfolge (hier: Strophe der Schwäbischen Kunde)
schwaebische_kunde$n_matches <- schwaebische_kunde$text %>%
str_count(pattern = "[eE]")
# Ergebnis anzeigen
schwaebische_kunde %>%
print(n = Inf)
Position des ersten Matches bestimmen: str_locate
Code: Alles auswählen
# 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
Code: Alles auswählen
# 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: str_extract
Code: Alles auswählen
# Tidyverse laden
library(tidyverse)
# Schwäbische Kunde laden
load("schwaebische_kunde.RData")
# Regex-Funktion ausführen
## (erstes) Auftreten von A bzw. A
schwaebische_kunde$first_match <- schwaebische_kunde$text %>%
str_extract(pattern = "[aA]")
# Ergebnis anzeigen
schwaebische_kunde %>%
print (n = Inf)
Alle Matches extrahieren: str_extract_all
Code: Alles auswählen
# 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]")
Gruppen extrahieren (nur erstes match): str_match
Code: Alles auswählen
# 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$text %>%
str_match(pattern = "([:alnum:]*)[:blank:]*[.,].*")
Gruppen extrahieren (alle matches): str_match_all
Code: Alles auswählen
# Tidyverse laden
library(tidyverse)
# Schwäbische Kunde laden
load("schwaebische_kunde.RData")
# Regex-Funktion ausführen
## Extrahiere alle Kleinbuchstaben, 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
Code: Alles auswählen
# 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
Code: Alles auswählen
# 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
Code: Alles auswählen
# 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" (viewforum.php?f=34) 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: 41775 (Hinweis: Laden erfolgt mit dem R-Befehl load("umfrage.RData")). Ordne ihren Antworten mithilfe 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 getrennt nach Versen (Zeilen) folgende Informationen möglichst übersichtlich angezeigt werden: die Zeilennummer des Verses, der gesamte Text des Verses sowie alle Großbuchstaben, die in diesem Vers 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 .
-------------
-------------
EDIT (12.07.2022): Korrektur eines Fehlers (fehlendes Quoting des (R-)Arbeitsverzeichnisses). Danke Huo!