Zum Inhalt springen

Regex-Muster, die jeder Entwickler kennen sollte

Eine praktische Referenz der regulären Ausdrücke, die du im Alltag wirklich brauchst — von Validierung über Parsen bis Suchen und Ersetzen.

4 Min. Lesezeit
Muster eines regulären Ausdrucks mit hervorgehobenen Übereinstimmungsgruppen in einem Beispieltext

Reguläre Ausdrücke lösen bei Entwicklern eine geradezu viszerale Reaktion aus. Die Syntax ist kryptisch, das Verhalten überraschend, und die Memes über „jetzt hast du zwei Probleme" sind wohlverdient. Aber Regex wird nicht verschwinden. Es taucht auf bei der Formularvalidierung, beim Parsen von Logs, bei Suchen und Ersetzen, beim Routing, bei Linting-Regeln und in Dutzenden weiterer Kontexte.

Das Problem ist nicht Regex an sich. Es ist, dass die meisten Entwickler Regex durch Versuch und Irrtum auf StackOverflow lernen, statt die Grundbausteine zu verstehen. Sobald man die Primitive kennt, wird das Zusammensetzen von Mustern vorhersehbar.

Die Grundbausteine

Jedes Regex-Muster ist eine Kombination aus sechs Konzepten: Literale, Zeichenklassen, Quantoren, Anker, Gruppen und Alternation. Das ist die gesamte Grundlage.

jsjavascript
// Literals: match exact characters
/hello/          // matches "hello" in "say hello world"
 
// Character classes: match any character in a set
/[aeiou]/        // matches any vowel
/[^0-9]/         // matches any non-digit
/\d/             // shorthand for [0-9]
/\w/             // shorthand for [a-zA-Z0-9_]
/\s/             // shorthand for whitespace
 
// Quantifiers: how many times to match
/a*/             // 0 or more 'a'
/a+/             // 1 or more 'a'
/a?/             // 0 or 1 'a'
/a{3}/           // exactly 3 'a's
/a{2,5}/         // between 2 and 5 'a's
 
// Anchors: position in the string
/^start/         // starts with "start"
/end$/           // ends with "end"
/\bword\b/       // whole word "word"

Das ist alles. Alles andere ist eine Zusammensetzung dieser sechs Konzepte. Das kryptisch wirkende Muster ^\w+@[\w.-]+\.\w{2,}$ bedeutet einfach: Anfang der Zeichenkette, ein oder mehrere Wortzeichen, das literale @, Wortzeichen/Punkte/Bindestriche, ein literaler Punkt, 2 oder mehr Wortzeichen, Ende der Zeichenkette.

Validierungsmuster

Formularvalidierung ist der häufigste Anwendungsfall für Regex. Diese Muster decken die Eingaben ab, die am häufigsten vorkommen.

tstypescript
const patterns = {
  // Email — simplified but practical
  // (Full RFC 5322 compliance requires a parser, not regex)
  email: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
 
  // URL — http/https with optional path
  url: /^https?:\/\/[\w.-]+(?:\.[\w.-]+)+[\w\-._~:/?#[\]@!$&'()*+,;=]*$/,
 
  // Phone — flexible international format
  phone: /^\+?[\d\s\-().]{7,20}$/,
 
  // Slug — URL-safe identifier
  slug: /^[a-z0-9]+(?:-[a-z0-9]+)*$/,
 
  // Hex color — 3 or 6 digit
  hexColor: /^#(?:[0-9a-fA-F]{3}){1,2}$/,
 
  // ISO date — YYYY-MM-DD
  isoDate: /^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])$/,
};
 
function validate(value: string, pattern: RegExp): boolean {
  return pattern.test(value);
}
tstypescript
// ❌ Overly strict email regex — rejects valid addresses
const strictEmail = /^[a-z]+\.[a-z]+@[a-z]+\.com$/;
// Rejects: user+tag@domain.co.uk, UPPER@domain.com
 
// ✅ Practical email regex — catches obvious errors
const practicalEmail = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
// Validates structure without being overly restrictive

Die Debatte über den richtigen E-Mail-Regex ist endlos. Die pragmatische Antwort: eine einfache strukturelle Prüfung per Regex, gefolgt von einer Bestätigung des Besitzes per Bestätigungs-E-Mail.

Capture-Gruppen und Extraktion

Gruppen () erfassen übereinstimmende Teilzeichenketten zur Extraktion. Benannte Gruppen (?<name>) machen die Ergebnisse selbsterklärend.

tstypescript
// Parse a log line with named groups
const logPattern = /^(?<timestamp>\d{4}-\d{2}-\d{2}T[\d:.]+Z)\s+(?<level>INFO|WARN|ERROR)\s+(?<message>.+)$/;
 
const line = '2020-12-02T14:30:00.000Z ERROR Connection timeout to database';
const match = line.match(logPattern);
 
if (match?.groups) {
  console.log(match.groups.timestamp); // 2020-12-02T14:30:00.000Z
  console.log(match.groups.level);     // ERROR
  console.log(match.groups.message);   // Connection timeout to database
}

Nicht erfassende Gruppen (?:) gruppieren, ohne zu erfassen — nützlich, wenn man eine Gruppierung für Quantoren braucht, aber nicht die Übereinstimmung selbst:

tstypescript
// Match file extensions — capture the name, not the dot group
const filePattern = /^(?<name>[\w.-]+)\.(?<ext>tsx?|jsx?|css|html)$/;
 
const match = 'component.tsx'.match(filePattern);
// match.groups.name = "component"
// match.groups.ext = "tsx"

Suchen-und-Ersetzen-Muster

Der wahre Produktivitätsgewinn von Regex liegt beim Ersetzen. Ein einziger Regex-Replace kann die Arbeit von 50 manuellen Änderungen erledigen.

tstypescript
// Convert camelCase to kebab-case
function toKebab(str: string): string {
  return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
}
// "backgroundColor" → "background-color"
 
// Strip HTML tags
function stripTags(html: string): string {
  return html.replace(/<[^>]*>/g, '');
}
 
// Mask sensitive data in logs
function maskEmail(text: string): string {
  return text.replace(
    /([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/g,
    '***@$2'
  );
}
// "Contact user@example.com" → "Contact ***@example.com"

Die Rückverweise $1, $2 in Ersetzungsstrings beziehen sich auf erfasste Gruppen. Das macht strukturelle Transformationen möglich, ohne dass geparst werden muss.

tstypescript
// Reformat dates from MM/DD/YYYY to YYYY-MM-DD
function reformatDate(text: string): string {
  return text.replace(
    /(\d{2})\/(\d{2})\/(\d{4})/g,
    '$3-$1-$2'
  );
}
// "12/02/2020" → "2020-12-02"

Lookahead und Lookbehind

Lookahead (?=) und Lookbehind (?<=) treffen auf Positionen, ohne Zeichen zu verbrauchen. Es sind Zusicherungen, keine Übereinstimmungen.

tstypescript
// Password validation — all conditions must be true
// At least 8 chars, one uppercase, one lowercase, one digit
const strongPassword = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/;
 
// Match numbers NOT followed by a unit (find raw numbers)
const rawNumbers = /\d+(?!\s*(?:px|em|rem|%))/g;
'16px 24 32rem 48'.match(rawNumbers); // ["24", "48"]
 
// Match currency amounts (number preceded by $)
const amounts = /(?<=\$)\d+(?:\.\d{2})?/g;
'Price: $19.99 and $5'.match(amounts); // ["19.99", "5"]

Lookaheads werden überall unterstützt. Lookbehinds erfordern ES2018+ (Chrome 62+, Node 8.10+, Firefox 78+). Für ältere Umgebungen stattdessen Capture-Gruppen verwenden.

Performance und Sicherheit

Regex kann gefährlich sein. Katastrophales Backtracking tritt auf, wenn ein Muster mit verschachtelten Quantoren auf eine Eingabe trifft, die eine exponentielle Durchsuchung erzwingt.

tstypescript
// ❌ Catastrophic backtracking — O(2^n) on bad input
const bad = /^(a+)+$/;
bad.test('aaaaaaaaaaaaaaaaaaaaaaab'); // Hangs for seconds
 
// ❌ Another common disaster — nested repetition
const evil = /^(\w+\s?)+$/;
evil.test('a b c d e f g h i j k !'); // Exponential backtracking
 
// ✅ Avoid nested quantifiers on overlapping patterns
const safe = /^[a\s]+$/;
const alsoSafe = /^\w+(?:\s\w+)*$/;

Regeln für sicheren Regex-Einsatz:

  1. Niemals Quantoren in Mustern verschachteln, die auf dieselben Zeichen passen können
  2. Atomare Gruppen oder besitzergreifende Quantoren verwenden, wo verfügbar
  3. Beim Ausführen von benutzerdefinierten Regex-Mustern ein Timeout setzen
  4. Nicht-gierige Quantoren *? und +? bevorzugen, wenn die kürzeste Übereinstimmung benötigt wird
tstypescript
// When accepting regex from users, always set a timeout
function safeRegexTest(pattern: string, input: string, timeoutMs = 100): boolean {
  const start = performance.now();
  try {
    const regex = new RegExp(pattern);
    const result = regex.test(input);
    if (performance.now() - start > timeoutMs) {
      throw new Error('Regex execution exceeded timeout');
    }
    return result;
  } catch {
    return false;
  }
}

Die wichtigsten Erkenntnisse

  1. Regex hat sechs Grundbausteine — Literale, Zeichenklassen, Quantoren, Anker, Gruppen und Alternation decken alles ab
  2. Benannte Gruppen machen Muster lesbar — (?<name>...) erklärt sich selbst, anders als $1 und $2
  3. Validierungs-Regex sollte praktisch sein, nicht perfekt — eine einfache E-Mail-Prüfung plus eine Bestätigungs-E-Mail schlägt einen RFC-konformen Regex
  4. Suchen und Ersetzen ist die Regex-Fähigkeit mit dem größten Hebel — ein Muster kann 50 manuelle Änderungen ersetzen
  5. Vorsicht vor katastrophalem Backtracking — verschachtelte Quantoren auf überlappenden Mustern erzeugen exponentielle Laufzeiten
Wilfredo Rujel

Wilfredo Rujel

Full-Stack-Softwareentwickler

Diesen Beitrag teilenX