sub() und gsub() in R für String-Ersetzungen verwenden

R stellt mit sub() und gsub() zwei zentrale Basisfunktionen bereit, um Textmuster zu ersetzen. Beide Funktionen verwenden ein Suchmuster, einen Ersatzwert sowie einen Zeichenvektor oder eine Spalte aus einem Data Frame als Eingabe. Standardmäßig unterstützen beide Funktionen außerdem reguläre Ausdrücke. Der wichtigste Unterschied liegt im Umfang der Ersetzung: sub() ersetzt nur den ersten Treffer innerhalb jedes String-Elements, während gsub() alle passenden Vorkommen ersetzt.

Die Funktionen orientieren sich an Konventionen, die auch aus Unix-Werkzeugen wie sed bekannt sind, und gehören seit Beginn zu base R. Da sie Bestandteil von base R sind, müssen keine zusätzlichen Pakete installiert werden. Sie stehen daher in jeder normalen R-Installation zur Verfügung.

Auch in aktuellen R-Versionen werden sub() und gsub() häufig für Datenbereinigung, Textvorverarbeitung, Log-Verarbeitung und die Standardisierung von Spaltennamen eingesetzt.

Dieses Tutorial erklärt die Syntax und Argumente beider Funktionen, zeigt reguläre Ausdrücke mit Zeichenklassen, Ankern und Backreferences aus Capture Groups, behandelt fortgeschrittene Optionen wie case-insensitive Suche und die PCRE2-Engine über perl = TRUE, demonstriert das Ersetzen mehrerer Muster mit Reduce() und stringr::str_replace_all(), wendet gsub() auf Data-Frame-Spalten an und vergleicht gsub() mit Alternativen aus stringr und stringi.

Wichtige Punkte

  • Verwenden Sie sub(), wenn nur das erste passende Vorkommen pro String-Element ersetzt werden soll. Verwenden Sie gsub(), wenn alle Vorkommen ersetzt werden sollen.
  • Beide Funktionen unterstützen standardmäßig reguläre Ausdrücke. Mit fixed = TRUE wird das Suchmuster als normaler Literal-String interpretiert.
  • Mit perl = TRUE wechseln Sie von der Standard-TRE-Engine zu PCRE2. Dadurch werden Lookaheads, Lookbehinds, benannte Capture Groups sowie \U– und \L-Case-Modifier in Ersetzungsstrings verfügbar.
  • Mit \\1, \\2 und ähnlichen Referenzen können Capture Groups aus dem Suchmuster im Ersetzungsstring wiederverwendet werden.
  • Wenn mehrere unterschiedliche Muster in einem Ablauf ersetzt werden sollen, verwenden Sie stringr::str_replace_all() mit einem benannten Vektor oder verketten mehrere gsub()-Aufrufe mit Reduce().
  • gsub() kann direkt auf eine Data-Frame-Spalte angewendet werden, zum Beispiel mit df$col <- gsub("pattern", "replacement", df$col).
  • Für case-insensitive Suche setzen Sie ignore.case = TRUE. In Kombination mit \\b lassen sich ganze Wörter ersetzen. Beachten Sie jedoch, dass \\b in TRE nur ASCII-basiert arbeitet. Für Unicode-bewusste Wortgrenzen verwenden Sie perl = TRUE.
  • Beide Funktionen lassen NA-Werte unverändert und erzeugen dabei keinen Fehler. Wenn fehlende Werte erkannt oder ersetzt werden müssen, sollten sie vor dem Aufruf von sub() oder gsub() behandelt werden.

Voraussetzungen

Für dieses Tutorial benötigen Sie:

  • Eine lokale oder serverbasierte R-Installation.
  • Das Paket stringr für den Vergleichsabschnitt, optional installiert mit install.packages("stringr").

Was sind sub() und gsub() in R?

sub() und gsub() sind Basisfunktionen in R, mit denen ein Muster in einem Zeichenvektor gesucht und durch einen anderen String ersetzt wird. Das Muster kann entweder ein Literalwert oder ein regulärer Ausdruck sein. Beide Funktionen sind vektorisiert, sodass jedes Element des Eingabevektors unabhängig innerhalb eines einzigen Funktionsaufrufs verarbeitet wird.

sub(): Syntax und Parameter

Die vollständige Syntax von sub() lautet:

sub(pattern, replacement, x,
    ignore.case = FALSE, perl = FALSE, fixed = FALSE, useBytes = FALSE)

Die folgende Tabelle beschreibt die einzelnen Argumente:

Parameter Typ Beschreibung
pattern character Der String oder reguläre Ausdruck, nach dem gesucht wird.
replacement character Der Text, der anstelle jedes Treffers eingesetzt wird. Backreferences wie \\1 und \\2 werden unterstützt.
x character vector Der Eingabetext, in dem gesucht wird. Data-Frame-Spalten werden als Vektoren übergeben.
ignore.case logical Wenn TRUE gesetzt ist, wird Groß- und Kleinschreibung beim Matching ignoriert. Standard: FALSE.
perl logical Wenn TRUE gesetzt ist, verwendet R die PCRE2-Regex-Engine statt TRE. Standard: FALSE.
fixed logical Wenn TRUE gesetzt ist, wird das Muster als Literal-String statt als Regex behandelt. Standard: FALSE.
useBytes logical Wenn TRUE gesetzt ist, erfolgt das Matching byteweise. Das wird nur selten benötigt. Standard: FALSE.

gsub(): Syntax und Parameter

gsub() verwendet dieselbe Syntax und akzeptiert dieselben Argumente wie sub(). Auch der Ersetzungsstring unterstützt dieselbe Backreference-Schreibweise.

gsub(pattern, replacement, x,
     ignore.case = FALSE, perl = FALSE, fixed = FALSE, useBytes = FALSE)

Der einzige funktionale Unterschied zwischen beiden Funktionen wird in der folgenden Tabelle zusammengefasst:

Merkmal sub() gsub()
Ersetzungen pro Element Nur der erste Treffer Alle Treffer
Typischer Einsatzbereich Ein führendes Token entfernen oder ändern Globale Suche und Ersetzung durchführen
Syntax Identisch mit gsub() Identisch mit sub()
Regex-Unterstützung Ja Ja
Performance bei langen Strings Kann etwas schneller sein, da nach dem ersten Treffer gestoppt wird Durchsucht den gesamten String

Grundlegende Anwendungsbeispiele

Die folgenden Beispiele zeigen das grundlegende Verhalten von sub() und gsub() in praktischen Situationen.

Hinweis: Die R-Konsole richtet ausgegebene Vektorelemente zur besseren Lesbarkeit an der Länge des längsten Elements aus. Die exakten Leerzeichen in der Ausgabe können daher leicht abweichen.

Nur den ersten Treffer mit sub() ersetzen

sub() durchsucht jedes String-Element und stoppt, nachdem der erste Treffer ersetzt wurde.

# Replace the first occurrence of "R" in a tutorial description
tutorial_text <- "In this tutorial, we will install R and add packages from CRAN."
sub("R", "The R Language", tutorial_text)

Der Befehl gibt folgende Ausgabe zurück:

[1] "In this tutorial, we will install The R Language and add packages from CRAN."

Nur das erste "R" wird geändert. Da sub() pro String-Element nur den ersten Treffer ersetzt, bleiben spätere Treffer im selben String unverändert.

Alle Treffer mit gsub() ersetzen

gsub() durchsucht den gesamten String weiter und ersetzt jeden gefundenen Treffer. Wortgrenzen wie \\b helfen dabei, nur das gewünschte vollständige Wort zu erfassen und keine Teilzeichenfolge innerhalb eines anderen Wortes.

# Replace ALL standalone occurrences of "R" using word boundaries
tutorial_text <- "R is open-source. Use R for data analysis and R for visualization."
gsub("\\bR\\b", "The R Language", tutorial_text)

Die Ausgabe lautet:

[1] "The R Language is open-source. Use The R Language for data analysis and The R Language for visualization."

Jedes alleinstehende "R" wird ersetzt. Die Wortgrenze \\b ist dabei wichtig, da ein einfaches Muster "R" auch den Buchstaben innerhalb von Begriffen wie "CRAN" oder "TRE" treffen würde. Das könnte unerwünschte Ersetzungen verursachen.

sub() und gsub() auf eine Data-Frame-Spalte anwenden

Beide Funktionen können eine Data-Frame-Spalte als x-Argument erhalten. Übergeben Sie die Spalte an die Funktion, weisen Sie das Ergebnis zurück, und die Spalte wird aktualisiert.

# Create a sample data frame
marine_species <- data.frame(
  creature            = c("Starfish", "Blue Crab", "Bluefin Tuna", "Blue Shark", "Blue Whale"),
  population_millions = c(5, 6, 4, 2, 2),
  stringsAsFactors    = FALSE
)

# sub(): replace the first "Blue" in each element
sub("Blue", "Green", marine_species$creature)

Dieser Befehl gibt Folgendes zurück:

[1] "Starfish"      "Green Crab"    "Greenfin Tuna" "Green Shark"   "Green Whale"

"Bluefin Tuna" wird zu "Greenfin Tuna", weil "Blue" am Anfang von "Bluefin" steht. sub() erkennt vollständige Wörter nicht automatisch, sondern ersetzt jedes passende Vorkommen, auch innerhalb längerer Wörter. Um das Ergebnis im Data Frame zu speichern, weisen Sie es direkt der Spalte zu:

marine_species$creature <- sub("Blue", "Green", marine_species$creature)

Reguläre Ausdrücke mit sub() und gsub() verwenden

Standardmäßig interpretieren beide Funktionen pattern als regulären Ausdruck und verwenden dafür R’s TRE-Engine, eine modifizierte POSIX-ERE-Implementierung. Die folgenden Beispiele zeigen häufig verwendete Regex-Konstrukte.

Kurzübersicht zu Regex-Engines: Base R verwendet standardmäßig TRE. Mit perl = TRUE wird auf PCRE2 gewechselt. Das Paket stringr nutzt ICU-Regex über stringi. Diese Engine unterscheidet sich in Syntax und Verhalten leicht von TRE und PCRE2. Manche Funktionen sind nur in bestimmten Engines verfügbar.

Zeichenklassen und Wildcards verwenden

Eine Zeichenklasse wird in eckigen Klammern geschrieben und trifft genau ein Zeichen aus der definierten Menge. Eine negierte Klasse beginnt mit ^ und trifft jedes Zeichen, das nicht zu dieser Menge gehört.

# Remove all digits from product codes
product_codes <- c("SKU-1234", "SKU-5678", "SKU-ABCD")
gsub("[0-9]", "", product_codes)

Das Entfernen der Ziffern erzeugt:

[1] "SKU-"     "SKU-"     "SKU-ABCD"

Der Punkt . als Wildcard trifft ein einzelnes Zeichen außer einem Zeilenumbruch. Im nächsten Beispiel trifft der Punkt jedes Zeichen zwischen "l" und "g", einschließlich Buchstaben, Ziffern und Satzzeichen:

variants <- c("log", "lag", "l9g", "lg")
gsub("l.g", "[match]", variants)

Das Ergebnis ist:

[1] "[match]" "[match]" "[match]" "lg"

"lg" bleibt unverändert, weil zwischen "l" und "g" kein Zeichen vorhanden ist, das der Punkt treffen könnte. Quantifizierer wie + für ein oder mehr Zeichen und * für null oder mehr Zeichen erweitern Treffer über mehrere Zeichen hinweg. Wenn fortgeschrittene Regex-Konstrukte in unterschiedlichen Umgebungen möglichst einheitlich funktionieren sollen, kann perl = TRUE verlässlichere Ergebnisse liefern.

Anker (^ und $) in Mustern verwenden

Der Anker ^ trifft den Anfang eines Strings, während $ das Ende trifft. Anker sind hilfreich, wenn Inhalte am Anfang oder Ende entfernt werden sollen, ohne den mittleren Teil des Strings zu verändern.

# Remove trailing whitespace from column labels
messy_labels <- c("Revenue   ", "Costs  ", "Profit ")
gsub("\\s+$", "", messy_labels)

Die bereinigten Labels lauten:

[1] "Revenue" "Costs"   "Profit"

In R-String-Literalen benötigen Regex-Escape-Sequenzen doppelte Backslashes. Der Quellstring \\s wird in der Regex-Engine zu \s und steht dort für Whitespace. R’s TRE-Engine unterstützt \s als dokumentierte POSIX-ERE-Erweiterung, daher funktioniert dieses Beispiel ohne perl = TRUE. Für bessere Portabilität außerhalb von R oder zwischen verschiedenen Regex-Werkzeugen ist [[:space:]] die streng POSIX-kompatible Alternative.

Greedy Matching und Lazy Quantifier

Quantifizierer in R’s Regex-Engines sind standardmäßig greedy. Das bedeutet, sie erfassen so viel Text wie möglich, solange das gesamte Muster noch erfolgreich passt. Das kann zu unerwarteten Ergebnissen führen, wenn eigentlich der kürzeste mögliche Teilstring gesucht wird.

# Greedy: .* consumes from the first "<" to the LAST ">"
html_tags <- c("<b>bold</b>", "<em>italic</em>")
gsub("<.*>", "", html_tags)

Sie sollten diese Ausgabe sehen:

Innerhalb jedes String-Elements hat das greedy Muster .* alles zwischen dem ersten < und dem letzten > erfasst. Dadurch wurde der gesamte String-Inhalt entfernt. Um den kürzesten möglichen Bereich zu treffen, verwenden Sie den lazy Quantifier .*?. Dafür ist perl = TRUE erforderlich.

# Lazy: .*? stops at the NEAREST ">"
gsub("<.*?>", "", html_tags, perl = TRUE)

Das Ergebnis lautet:

.*? stoppt beim ersten erreichten >. Dadurch wird jedes einzelne Tag entfernt, während der Textinhalt erhalten bleibt.

Sonderzeichen escapen

Regex-Metazeichen wie ., *, +, ?, (, ), [, ], {, }, ^, $, | und \ müssen mit \\ escaped werden, wenn sie wörtlich gesucht werden sollen.

# Replace literal dots in a version string with hyphens
version_string <- "R 4.6.0 released"
gsub("\\.", "-", version_string)

Das Ersetzen der Punkte ergibt:

Alternativ kann fixed = TRUE gesetzt werden. Dadurch wird Regex-Parsing deaktiviert. gsub(".", "-", version_string, fixed = TRUE) erzeugt dasselbe Ergebnis, ohne dass ein Escape notwendig ist. Verwenden Sie fixed = TRUE, wenn das Muster keine Regex-Logik enthält und immer wörtlich gesucht werden soll. Wenn fixed = TRUE aktiv ist, sind Regex-Metazeichen und PCRE-Funktionen deaktiviert, weil das Muster als Plain Text behandelt wird. Eine Kombination mit perl = TRUE hat dann keine Wirkung.

Fortgeschrittene Techniken für Pattern Matching

Die folgenden Techniken behandeln komplexere Anwendungsfälle, darunter case-insensitive Ersetzungen, Backreferences aus Capture Groups und PCRE2-Funktionen, die über perl = TRUE verfügbar sind.

Case-insensitive Ersetzung mit ignore.case = TRUE

Pattern Matching ist standardmäßig case-sensitive. Setzen Sie ignore.case = TRUE, damit das Muster unabhängig von Groß- und Kleinschreibung gefunden wird.

# Normalize mixed-case product labels to a standard form
product_labels <- c("Widget Pro", "WIDGET PRO", "widget pro", "Super Widget Pro")
gsub("\\bwidget pro\\b", "StandardWidget", product_labels, ignore.case = TRUE)

Nach der Normalisierung lauten die Labels:

[1] "StandardWidget"      "StandardWidget"      "StandardWidget"      "Super StandardWidget"

Die Wortgrenze \\b beschränkt den Treffer auf die vollständige Phrase und verhindert Treffer innerhalb längerer Wörter. ignore.case = TRUE funktioniert sowohl mit sub() als auch mit gsub() und ist mit TRE sowie PCRE2 kompatibel.

Backreferences und Capture Groups verwenden

Klammern in einem Muster erzeugen Capture Groups. Im Ersetzungsstring verweist \\1 auf die erste Gruppe, \\2 auf die zweite Gruppe und so weiter. Dadurch kann erfasster Text an einer anderen Position wiederverwendet werden.

# Reformat "First Last" names to "Last, First"
full_names <- c("Alice Johnson", "Bob Martinez", "Carol White")
gsub("(\\w+) (\\w+)", "\\2, \\1", full_names)

Die umformatierten Namen sind:

[1] "Johnson, Alice"  "Martinez, Bob"   "White, Carol"

Dieses einfache Beispiel geht davon aus, dass genau zwei Wörter durch ein Leerzeichen getrennt sind. Es berücksichtigt keine zweiten Vornamen, Nachnamen mit Bindestrich oder Apostrophe in Namen wie "O'Brien". Für produktive Workflows sollte ein genaueres Muster oder eine spezialisierte Name-Parsing-Bibliothek verwendet werden. Außerdem verhalten sich Zeichenklassen wie \\w mit perl = TRUE oder ICU-basierten Engines konsistenter, wenn die Eingabe Unicode-Zeichen enthalten kann. Im Standardmodus von TRE trifft \\w nur ASCII-Wortzeichen.

Backreferences eignen sich auch zum Umformatieren strukturierter Werte wie Datumsangaben.

# Reformat ISO dates (YYYY-MM-DD) to US format (MM/DD/YYYY)
iso_dates <- c("2025-03-15", "2024-11-01", "2026-06-04")
gsub("(\\d{4})-(\\d{2})-(\\d{2})", "\\2/\\3/\\1", iso_dates)

Die konvertierten Datumswerte im US-Format sind:

[1] "03/15/2025" "11/01/2024" "06/04/2026"

PCRE mit perl = TRUE aktivieren

Mit perl = TRUE wird die Regex-Engine von TRE auf PCRE2 umgestellt.

PCRE2 bietet stärkere Unicode-Unterstützung und erweiterte Regex-Funktionen für UTF-8-Text. Außerdem werden Funktionen verfügbar, die TRE nicht unterstützt, darunter Lookaheads, Lookbehinds, benannte Capture Groups, possessive Quantifier sowie die Case-Conversion-Modifier \U und \L in Ersetzungsstrings.

# Use \U to uppercase each word (PCRE2 case modifier, perl = TRUE required)
product_names <- c("widget pro", "super gadget", "nano device")
gsub("(\\w)(\\w*)", "\\U\\1\\L\\2", product_names, perl = TRUE)

Das Umwandeln in Title Case erzeugt:

[1] "Widget Pro"   "Super Gadget" "Nano Device"

\\U\\1 schreibt das erste Zeichen jedes Wortes groß, während \\L\\2 die übrigen Zeichen kleinschreibt. Diese Operatoren funktionieren nur in PCRE2-Ersetzungsstrings und haben ohne perl = TRUE keine Wirkung.

Lookaheads und Lookbehinds mit perl = TRUE

Lookaheads wie (?=...) und Lookbehinds wie (?<=...) sind Zero-Width Assertions. Sie treffen eine Position abhängig davon, was danach oder davor steht, ohne die umgebenden Zeichen selbst zu verbrauchen. Diese Funktionen gehören zu PCRE2 und erfordern perl = TRUE.

# Insert an underscore between a letter and a digit (e.g., "Revenue2024" to "Revenue_2024")
field_names <- c("Revenue2024", "Costs2024", "Profit2024")
gsub("(?<=[A-Za-z])(?=[0-9])", "_", field_names, perl = TRUE)

Die aktualisierten Feldnamen sind:

[1] "Revenue_2024" "Costs_2024"   "Profit_2024"

Der Lookbehind (?<=[A-Za-z]) prüft, ob vor der aktuellen Position ein Buchstabe steht. Der Lookahead (?=[0-9]) prüft, ob danach eine Ziffer folgt. An genau dieser Position wird ein Unterstrich eingefügt, ohne die umgebenden Zeichen zu verbrauchen.

Mehrere Muster in R ersetzen

Ein einzelner gsub()-Aufruf akzeptiert nur ein Muster. Wenn mehrere unterschiedliche Muster in einem Ablauf ersetzt werden sollen, verwenden Sie verkettete gsub()-Aufrufe mit Reduce() oder stringr::str_replace_all(), das einen benannten Vektor mit Muster-Ersetzungs-Paaren akzeptiert.

Mehrere gsub()-Ersetzungen mit Reduce() anwenden

Erstellen Sie einen benannten Character-Vektor, bei dem jeder Name das Suchmuster und jeder Wert die Ersetzung ist. Anschließend kann Reduce() verwendet werden, um jede Ersetzung nacheinander anzuwenden.

# Expand SMS-style abbreviations in survey responses
survey_responses <- c("pls send info asap", "thx for ur help", "gr8 service btw")

replacements <- c(
  "pls"  = "please",
  "asap" = "as soon as possible",
  "thx"  = "thanks",
  "ur"   = "your",
  "gr8"  = "great",
  "btw"  = "by the way"
)

result <- Reduce(
  function(text, pat) gsub(pat, replacements[pat], text, fixed = TRUE),
  names(replacements),
  init = survey_responses
)
result

Die ausgeschriebenen Abkürzungen ergeben:

[1] "please send info as soon as possible"
[2] "thanks for your help"
[3] "great service by the way"

Reduce() führt jeden gsub()-Aufruf der Reihe nach aus und übergibt das Ergebnis eines Schritts an den nächsten. Die Reihenfolge der Werte in replacements ist wichtig, wenn eine Ersetzung Text erzeugen kann, der von einem späteren Muster ebenfalls getroffen wird. Das folgende Beispiel zeigt dieses Verhalten:

# Hazardous order: "cat" is replaced by "dog", then "dog" is replaced by "wolf"
chained_replacements <- c("cat" = "dog", "dog" = "wolf")
Reduce(
  function(text, pat) gsub(pat, chained_replacements[pat], text, fixed = TRUE),
  names(chained_replacements),
  init = "my cat and my dog"
)

Die verketteten Ersetzungen erzeugen:

Sowohl "cat" als auch "dog" werden zu "wolf", weil die erste Ersetzung "cat" in "dog" umwandelt und dieses Ergebnis anschließend von der zweiten Ersetzung getroffen wird. Um das zu vermeiden, ordnen Sie Ersetzungen so an, dass spätere Muster keine früheren Ausgaben treffen, oder verwenden Sie str_replace_all() mit einem benannten Vektor. Diese Variante wendet Ersetzungen auf den ursprünglichen String an, statt auf Text, der sich nach jedem Schritt verändert.

stringr::str_replace_all() mit einem benannten Vektor verwenden

stringr::str_replace_all() kann denselben benannten Vektor direkt verarbeiten. Dadurch wird das Ersetzen mehrerer Muster kürzer und besser lesbar.

library(stringr)

result <- str_replace_all(survey_responses, replacements)
result

str_replace_all() liefert dasselbe Ergebnis:

[1] "please send info as soon as possible"
[2] "thanks for your help"
[3] "great service by the way"

Beide Methoden erzeugen dieselbe Ausgabe. str_replace_all() ist häufig besser lesbar, wenn die Ersetzungsliste mehr als zwei oder drei Einträge enthält, und passt natürlich in |>– und %>%-Pipelines.

gsub() und sub() auf Data Frames anwenden

Die Anwendung beider Funktionen auf eine Data-Frame-Spalte funktioniert genauso wie bei einem Character-Vektor: Die Spalte wird als x übergeben, und der Rückgabewert wird der Spalte wieder zugewiesen. Die folgenden Abschnitte zeigen Ersetzungen in einer einzelnen Spalte, Ersetzungen über mehrere Spalten mit lapply() und ein praktisches Beispiel zur Datenbereinigung.

Ein wichtiges Verhalten bei echten Daten ist, dass beide Funktionen NA-Werte beibehalten. Ist ein Vektorelement vor dem Funktionsaufruf NA, bleibt es auch danach NA, ohne einen Fehler auszulösen.

# NA values are preserved, not replaced or raised as errors
gsub("cat", "dog", c("cat", NA, "catfish"))

Der NA-Wert bleibt unverändert:

Wenn eine Bereinigungspipeline fehlende Werte erkennen oder ersetzen muss, behandeln Sie NA-Werte vor dem Aufruf von gsub(), statt zu erwarten, dass die Ersetzung sie verändert.

Werte in einer einzelnen Spalte ersetzen

Um gsub() auf eine einzelne Data-Frame-Spalte anzuwenden, übergeben Sie die Spalte als x-Argument und weisen das Ergebnis derselben Spalte wieder zu.

# Clean a price column from a CSV import
sales_data <- data.frame(
  product = c("Laptop", "Phone", "Tablet", "Monitor"),
  price   = c("$1,299", "$899", "$2,450", "$349"),
  stringsAsFactors = FALSE
)

# The character class [$,] matches either $ or , in a single regex pass
sales_data$price <- as.numeric(gsub("[$,]", "", sales_data$price))
sales_data

Der bereinigte Data Frame sieht so aus:

  product price
1  Laptop  1299
2   Phone   899
3  Tablet  2450
4 Monitor   349

gsub() mit lapply() auf mehrere Spalten anwenden

Um dieselbe Transformation auf mehrere Spalten anzuwenden, ohne denselben Funktionsaufruf mehrfach zu schreiben, verwenden Sie eine Spaltenauswahl zusammen mit lapply().

# Strip formatting from phone number columns
contact_data <- data.frame(
  primary_phone   = c("(555) 123-4567", "(555) 987-6543"),
  secondary_phone = c("(555) 111-2222", "(555) 333-4444"),
  stringsAsFactors = FALSE
)

phone_cols <- c("primary_phone", "secondary_phone")

contact_data[phone_cols] <- lapply(contact_data[phone_cols], function(col) {
  gsub("[^0-9]", "", col)
})

contact_data

Die bereinigten Telefonnummern lauten:

  primary_phone secondary_phone
1    5551234567      5551112222
2    5559876543      5553334444

lapply() gibt eine Liste zurück, die R automatisch wieder den ausgewählten Spalten zuweisen kann.

Praktisches Beispiel zur Datenbereinigung

Das nächste Beispiel bereinigt einen Data Frame, der einen Rohimport aus einer CSV-Datei mit uneinheitlicher Zahlenformatierung und gemischten Datumstrennzeichen darstellt.

# Simulate a messy CSV import
orders <- data.frame(
  order_id   = c("ORD-001", "ORD-002", "ORD-003"),
  amount     = c("$1,299.00", "$ 450.50", "$3,000.00"),
  order_date = c("01-15-2025", "02/03/2025", "2025.03.10"),
  stringsAsFactors = FALSE
)

# Step 1: strip currency symbol, spaces, and commas; convert to numeric
orders$amount <- as.numeric(gsub("[$,\\s]", "", orders$amount))

# Step 2: normalize all date separators to hyphens
orders$order_date <- gsub("[/.]", "-", orders$order_date)

orders

Nach beiden Bereinigungsschritten sieht der Data Frame so aus:

  order_id  amount order_date
1  ORD-001 1299.00 01-15-2025
2  ORD-002  450.50 02-03-2025
3  ORD-003 3000.00 2025-03-10

Zwei vektorisierte gsub()-Aufrufe führen die Normalisierung sauber aus, ohne explizite Schleifen oder zusätzliche Pakete.

sub() und gsub() vs. stringr: Wann welche Option sinnvoll ist

gsub() und stringr::str_replace_all() ersetzen beide alle Mustertreffer in einem Character-Vektor. Welche Option besser passt, hängt meist von Abhängigkeiten, Pipeline-Stil und benötigten Funktionen ab.

Vergleichstabelle: gsub() vs. str_replace_all()

Die folgende Tabelle fasst die wichtigsten Entscheidungspunkte zusammen.

Merkmal gsub() str_replace_all()
Paket base R, keine Installation erforderlich stringr, Teil des tidyverse-Ökosystems
Mehrere Muster in einem Aufruf Nein Ja, mit einem benannten Vektor
Standard-Regex-Engine TRE, POSIX ERE ICU über stringi
PCRE-Unterstützung Ja, mit perl = TRUE Immer ICU
Pipeline-Kompatibilität Mittel Hoch, nativ mit |> oder %>%
Unicode-Unterstützung Gut, sehr gut mit perl = TRUE Sehr gut, da immer ICU verwendet wird
Externe Abhängigkeit Keine stringr plus stringi

Performance bei großen Vektoren

Bei Ersetzungen mit einem einzelnen Muster auf typischen Vektoren verhalten sich gsub() und str_replace_all() meist ähnlich. Bei großen Datenmengen mit festen, nicht-regulären Mustern ist stringi::stri_replace_all_fixed() häufig schneller, weil es auf Literal-String-Matching statt auf vollständiges Regex-Parsing optimiert ist.

str_replace_all() kann komfortabler sein und je nach Workload besser abschneiden als mehrere verkettete gsub()-Aufrufe. Für performancekritische Datenpipelines sollten Sie immer mit den echten Daten benchmarken, bevor Sie eine Option als schneller annehmen.

Das folgende Beispiel nutzt stringi für eine Fixed-String-Ersetzung:

library(stringi)

# High-performance fixed-string replacement using stringi
product_descriptions <- c("apple and apple pie", "apple juice", "pineapple")
stri_replace_all_fixed(product_descriptions, "apple", "pear")

Die Ersetzung gibt Folgendes zurück:

[1] "pear and pear pie" "pear juice"        "pinepear"

Eine Literal-Ersetzung betrifft auch Teilstrings innerhalb längerer Wörter. stri_replace_all_fixed() ersetzt "apple" innerhalb von "pineapple", wodurch "pinepear" entsteht. Das ist bei Literal-Match-Funktionen erwartetes Verhalten. Verwenden Sie stri_replace_all_regex() mit einer Wortgrenze wie \\bapple\\b, wenn nur ganze Wörter getroffen werden sollen.

Unicode und Multibyte-Strings verarbeiten

Aktuelle R-Versionen bieten deutlich verbesserte UTF-8-Unterstützung auf verschiedenen Plattformen.

Für Daten mit Nicht-ASCII-Zeichen, Emojis oder nicht-lateinischen Schriftsystemen sind zwei Ansätze meist besonders verlässlich: Verwenden Sie perl = TRUE mit gsub(), um die Unicode-Unterstützung von PCRE2 zu aktivieren, oder nutzen Sie str_replace_all(), das über stringi immer auf die ICU-Engine zurückgreift.

Wenn Multibyte-Text nicht wie erwartet getroffen wird, prüfen Sie die Kodierung mit Encoding(x) und normalisieren Sie bei Bedarf vor dem Aufruf von gsub() mit enc2utf8(x) auf UTF-8.

Häufige Fehler und Lösungen

Die folgenden Abschnitte erklären vier typische Ursachen für unerwartetes Verhalten bei sub() und gsub() sowie konkrete Lösungsansätze.

Fehler „invalid regular expression“

Dieser Fehler tritt auf, wenn das Argument pattern nicht korrekt escapte Metazeichen oder ungültige Regex-Syntax enthält. Häufige Ursachen sind nicht geschlossene Klammern, nicht escapte eckige Klammern oder nicht geschlossene Quantifizierer.

# Unmatched "(" causes an invalid regular expression error
gsub("(error", "warning", "connection (error) occurred")

R gibt einen Fehler aus, statt ein Ergebnis zurückzugeben:

Error in gsub("(error", "warning", "connection (error) occurred") :
  invalid regular expression '(error', reason 'Missing ')''

Beheben Sie das Problem, indem Sie die Klammer mit \\( escapen. Alternativ können Sie fixed = TRUE verwenden, wenn der Suchwert als Literal-String behandelt werden soll.

# Escaped version
gsub("\\(error", "warning", "connection (error) occurred")

Mit escapeter Klammer gibt R Folgendes zurück:

[1] "connection warning) occurred"

Backslash-Escaping in Mustern und Ersetzungsstrings

R-String-Literale benötigen doppelte Backslashes, also \\, um einen einzelnen Regex-Backslash \ darzustellen. Eine Regex, die einen Literal-Backslash treffen soll, benötigt im R-Quelltext vier Backslashes. Der String "\\\\" wird zur zweizeichigen Regex \\, die von der Engine als ein wörtlicher Backslash interpretiert wird.

Dieselbe Doppel-Backslash-Regel gilt auch für das Argument replacement. Um eine Backreference in einem Ersetzungsstring zu verwenden, schreiben Sie "\\1" im R-Quelltext. Die Regex-Engine sieht \1 und ersetzt es durch die erste Capture Group. Um einen wörtlichen Backslash in die Ausgabe einzufügen, schreiben Sie "\\\\" im R-Quelltext. Die Engine sieht \\ und gibt einen einzelnen \ aus.

# Replace backslashes in a Windows-style file path with forward slashes
file_path <- "C:\\Users\\alice\\Documents"
gsub("\\\\", "/", file_path)

Der normalisierte Pfad lautet:

[1] "C:/Users/alice/Documents"

Unerwartetes Verhalten mit fixed = TRUE und Regex-Mustern

Wenn fixed = TRUE aktiviert ist, verlieren Regex-Metazeichen ihre Sonderbedeutung und werden wörtlich gesucht. Wird ein Muster wie [0-9]+ zusammen mit fixed = TRUE verwendet, sucht R nach dem Literaltext "[0-9]+" statt nach Ziffern. Wenn weniger Ersetzungen stattfinden als erwartet, prüfen Sie, ob fixed = TRUE versehentlich aktiviert wurde.

Das Muster trifft mehr als beabsichtigt

Muster ohne Anker treffen überall im String, auch innerhalb längerer Wörter. Verwenden Sie ^ und $, um den Treffer auf den gesamten String zu beschränken, oder \\b für Wortgrenzen. Die Kombination aus ignore.case = TRUE und \\b ist ein zuverlässiger Ansatz für case-insensitive Ersetzungen ganzer Wörter.

FAQ

Was ist der Unterschied zwischen sub() und gsub() in R?

Der wichtigste Unterschied liegt darin, wie viele Treffer pro String-Element ersetzt werden.

sub() ersetzt nur das erste Vorkommen des angegebenen Musters innerhalb jedes Elements eines Character-Vektors. Das ist sinnvoll, wenn nur der erste Treffer geändert oder entfernt werden soll, etwa beim Entfernen eines einzelnen Präfixes, während spätere Vorkommen unverändert bleiben.

gsub() ersetzt jedes Vorkommen des Musters im gesamten String-Element. Dadurch eignet sich die Funktion besonders für globale Such-und-Ersetzungs-Aufgaben und umfassende Datenbereinigung.

Beide Funktionen nutzen dieselbe Syntax und akzeptieren dieselben Argumente. Ein Wechsel von einer Funktion zur anderen erfordert daher meist nur das Ändern des Funktionsnamens. In vielen Bereinigungs- und Normalisierungsworkflows wird gsub() häufiger genutzt, weil es global ersetzt. Wählen Sie sub(), wenn nur der erste Treffer gezielt kontrolliert werden soll.

Wie ersetze ich mehrere unterschiedliche Muster gleichzeitig mit gsub() in R?

Base R’s gsub() kann nicht mehrere unterschiedliche Muster in einem einzigen Aufruf ersetzen. Es gibt jedoch zwei gängige Vorgehensweisen.

Verkettung mit Reduce(): Erstellen Sie einen benannten Character-Vektor, bei dem die Namen die Muster und die Werte die Ersetzungen sind. Anschließend wenden Sie mit Reduce() eine Wrapper-Funktion auf jedes Muster-Ersetzungs-Paar nacheinander an.

patterns <- c("foo" = "bar", "baz" = "qux")
text <- "foo and baz"
Reduce(function(x, y) gsub(y, patterns[y], x), names(patterns), init = text)

Verwendung von stringr::str_replace_all(): Die Funktion str_replace_all() aus stringr akzeptiert direkt einen benannten Vektor mit Muster-Ersetzungs-Paaren. Dadurch können alle Ersetzungen in einer Zeile formuliert werden.

library(stringr)
str_replace_all(text, patterns)

str_replace_all() ist empfehlenswert, wenn mehr als wenige Muster verarbeitet werden, da der Code übersichtlicher und wartbarer bleibt, besonders in tidyverse-Workflows.

Wie mache ich gsub() in R case-insensitive?

Für case-insensitive Suche mit gsub() setzen Sie ignore.case auf TRUE:

gsub("hello", "hi", x, ignore.case = TRUE)

Dadurch werden alle Varianten von "hello" unabhängig von der Groß- und Kleinschreibung ersetzt, zum Beispiel "Hello" oder "HELLO". Wenn verhindert werden soll, dass dieselben Buchstaben innerhalb eines anderen Wortes getroffen werden, etwa "hello" in "chello", kombinieren Sie ignore.case = TRUE mit einer Wortgrenze:

gsub("\\bhello\\b", "hi", x, ignore.case = TRUE)

So wird die Ersetzung auf vollständige Wörter beschränkt.

Was bewirkt perl = TRUE in gsub() und sub()?

Das Argument perl = TRUE weist R an, statt der Standard-TRE-Engine die PCRE2-Engine zu verwenden. Dadurch werden erweiterte Regex-Funktionen verfügbar, darunter:

  • Lookaheads wie (?=...) und Lookbehinds wie (?<=...)
  • Benannte Capture Groups wie (?<name>...)
  • Possessive Quantifier wie *+ und ++
  • Case-Conversion-Operatoren wie \\U, \\L und \\E in Ersetzungen
  • Verbesserte Unicode-Unterstützung für UTF-8-Daten

Wenn ein Muster oder eine Ersetzung auf fortgeschrittene Regex-Funktionen angewiesen ist, die nur PCRE2 bereitstellt, setzen Sie perl = TRUE.

Wie verwende ich Backreferences in gsub()-Ersetzungsstrings?

Backreferences ermöglichen es, gefundene Gruppen aus dem Muster im Ersetzungsstring erneut zu verwenden. Setzen Sie dazu den Teil des Musters, der erfasst werden soll, in Klammern. Jedes Klammerpaar erzeugt eine nummerierte Capture Group. Anschließend referenzieren Sie diese Gruppen in der Ersetzung mit \\1, \\2 und so weiter entsprechend ihrer Reihenfolge.

Beispiel:

gsub("(\\w+) (\\w+)", "\\2, \\1", "John Smith")
# Result: "Smith, John"

Mit perl = TRUE kann der Treffer zusätzlich durch Case-Modifier erweitert werden. Beispielsweise schreibt \\U\\1 eine Gruppe groß und \\L\\2 eine Gruppe klein. Dadurch sind komplexere String-Transformationen möglich.

Wie wende ich gsub() auf eine Spalte in einem Data Frame an?

Um gsub() auf eine einzelne Spalte anzuwenden, übergeben Sie die Spalte an die Funktion und weisen das Ergebnis zurück:

df$column <- gsub("pattern", "replacement", df$column)

Für mehrere Spalten kann lapply() verwendet werden, um dieselbe Ersetzung auf alle ausgewählten Spalten anzuwenden:

df[cols] <- lapply(df[cols], function(col) gsub("pattern", "replacement", col))

Diese Methode skaliert gut und vermeidet, dass derselbe gsub()-Aufruf für jede Spalte wiederholt werden muss. Das ist besonders hilfreich beim Bereinigen und Standardisieren größerer Datensätze.

Sollte ich gsub() oder stringr::str_replace_all() in R verwenden?

Die Entscheidung hängt vom Projektkontext und den Anforderungen ab.

Verwenden Sie gsub(), wenn eine Lösung ohne externe Abhängigkeiten bevorzugt wird, wenn PCRE2-spezifische Funktionen über perl = TRUE benötigt werden oder wenn Benchmarks zeigen, dass es für den jeweiligen Anwendungsfall optimal ist. Die Funktion ist in base R enthalten und erfordert keine zusätzliche Installation.

Verwenden Sie stringr::str_replace_all() für tidyverse-orientierte Workflows, wenn mehrere Muster gleichzeitig ersetzt werden sollen oder wenn moderne, konsistente Unicode-Verarbeitung über die ICU-Engine von stringi gewünscht ist. Außerdem lässt sich die Funktion gut in Datenpipelines integrieren und kann Ersetzungszuordnungen mit benannten Vektoren lesbarer machen.

Die passende Wahl hängt von Workflow-Präferenzen, benötigten Funktionen und der Komplexität der Ersetzungsaufgabe ab.

Warum ersetzt gsub() mein Muster nicht wie erwartet?

Mehrere typische Ursachen können dazu führen, dass gsub() ein Muster nicht wie erwartet ersetzt.

Nicht escapte Regex-Sonderzeichen: Regex-Metazeichen wie ., *, +, [, ], (, ), |, ?, ^ und $ haben in Mustern besondere Bedeutungen. Um sie wörtlich zu treffen, setzen Sie entweder fixed = TRUE oder escapen jedes Metazeichen mit doppelten Backslashes. Zum Beispiel trifft \\. einen wörtlichen Punkt.

PCRE2-only-Funktionen ohne perl = TRUE: Erweiterte Regex-Konstrukte wie Lookahead, Lookbehind und benannte Capture Groups benötigen perl = TRUE. Aktivieren Sie diese Option, wenn das Muster darauf angewiesen ist.

Kodierungsprobleme mit Nicht-ASCII-Strings: Wenn die Eingabe Unicode-Zeichen enthält, können Kodierungsprobleme verhindern, dass Muster getroffen werden. Prüfen Sie die Kodierung mit Encoding(x) und konvertieren Sie bei Bedarf vor gsub() mit enc2utf8(x) nach UTF-8.

Nicht verankerte Muster treffen zu viel Text: Ein Muster ohne Anker kann innerhalb längerer Wörter oder Teilstrings treffen und dadurch unerwünschte Ersetzungen auslösen. Verwenden Sie \\b, ^ oder $, um Treffer auf den gewünschten Bereich zu beschränken.

Tipp: Testen Sie das Muster zuerst mit grepl(pattern, x), um zu prüfen, ob es genau das trifft, was Sie erwarten, bevor Sie gsub() für die Ersetzung verwenden.

Fazit

sub() und gsub() sind grundlegende base-R-Funktionen für String-Ersetzungen. Sie funktionieren mit Character-Vektoren, Data-Frame-Spalten und allen Objekten, die in Zeichenketten umgewandelt werden können, ohne externe Pakete zu benötigen. sub() ersetzt den ersten Treffer pro Element, während gsub() jeden Treffer ersetzt. Regex-Unterstützung über die TRE-Engine deckt die meisten Anwendungsfälle ab, und perl = TRUE aktiviert PCRE2-Funktionen wie Lookaheads, Lookbehinds und Case-Modifier für fortgeschrittene Formatierungsaufgaben. Wenn mehrere Muster in einem einzigen Aufruf ersetzt werden sollen oder eine tidyverse-kompatible Pipeline wichtig ist, ist stringr::str_replace_all() eine passende Ergänzung.

Quelle: digitalocean.com

Jetzt 200€ Guthaben sichern

Registrieren Sie sich jetzt in unserer ccloud³ und erhalten Sie 200€ Startguthaben für Ihr Projekt.

Das könnte Sie auch interessieren:

Moderne Hosting Services mit Cloud Server, Managed Server und skalierbarem Cloud Hosting für professionelle IT-Infrastrukturen

Serverless LLM-Inferenz: Wichtige Leistungskennzahlen

AI/ML, Tutorial
Vijonavor 3 Stunden Wichtige Leistungskennzahlen für produktive serverlose LLM-Inferenz Wenn Teams serverlose LLM-Inferenzmodelle und Plattformen miteinander vergleichen, konzentriert sich die Bewertung häufig auf einen einzigen Wert: die mediane Anzahl an Tokens…