Regex Builder
Regex Builder – opanuj wyrażenia regularne bez bólu głowy
Wyrażenia regularne potrafią być… brutalne. Pełne znaków specjalnych, trudne do czytania i jeszcze trudniejsze do napisania od zera.
Regex Builder powstał po to, żeby to zmienić.
To interaktywna aplikacja do nauki i testowania wyrażeń regularnych w JavaScript, która pozwala budować regexy z klocków, testować je na żywo i rozumieć, co dokładnie robi każdy fragment.
Buduj regex krok po kroku
Nie musisz już pamiętać całej składni regex na pamięć.
Zamiast tego:
- składasz wyrażenie z gotowych elementów (np. „dowolna liczba”, „słowo”, „email”, „grupa”)
- widzisz od razu, jak wygląda wynikowy regex
- możesz w każdej chwili edytować lub rozbić go na części
Regex przestaje być czarną magią — staje się konstrukcją.
Testuj i ucz się na żywo
- natychmiastowe podświetlanie dopasowań w tekście
- lista wszystkich matchy
- obsługa flag (
g,i,m, itd.) - szybka informacja o błędach składni
Każda zmiana w regexie od razu pokazuje efekt.
Explain Regex – zrozum, co naprawdę się dzieje
Każdy fragment wyrażenia:
- jest opisany prostym językiem
- pokazuje swoje znaczenie i zakres działania
- pomaga zrozumieć dlaczego regex działa (lub nie)
Idealne narzędzie do nauki, powtórek i „aha momentów”.
Dla kogo?
- dla początkujących, którzy boją się regexów
- dla programistów, którzy „kopiują z internetu i modlą się, żeby działało”
- dla nauczycieli i studentów
- dla każdego, kto chce rozumieć, a nie tylko używać
Dlaczego warto?
Składnia regex JavaScript
Znaki meta
- a|b – Pasuje do a lub b
- . – Dopasowuje dowolny znak (symbol wieloznaczny) z wyjątkiem znaków kończących wiersz
- \w – Dopasowuje znaki słowa (alfanumeryczne i _)
- \W – Dopasowuje znaki niebędące słowami
- \d – Dopasowuje cyfry (0-9)
- \D – Dopasowuje znaki niebędące cyframi
- \s – Dopasowuje znaki odstępu (spacja, tabulator, nowy wiersz)
- \S – Dopasowuje znak inny niż biały
- [\b] – Dopasowuje znaki cofania
- \0 – Dopasowuje znaki NULL
- \n – Dopasowuje znaki nowego wiersza
- \f – Dopasowuje znaki końca linii
- \r – Dopasowuje znaki powrotu karetki
- \t – Dopasowuje znaki tabulacji
- \v – Dopasowuje znaki tabulacji pionowej
- \p{} – Dopasowuje znaki o podanej właściwości Unicode
- \P{} – Dopasowuje znak NIE o podanej właściwości Unicode
- \ddd – Dopasowuje znak o liczbie ósemkowej ddd
- \xhh – Dopasowuje znak o liczbie szesnastkowej hh
- \uhhhh – Dopasowuje znak Unicode o liczbie szesnastkowej hhhh
Klasy znaków
- [a] – Dopasowuje znak w nawiasach kwadratowych
- [^a] – Dopasowuje wszystkie znaki NIE znajdujące się w nawiasach kwadratowych
- [abc] – Dopasowuje wszystkie znaki w nawiasach kwadratowych
- [^abc] – Dopasowuje wszystkie znaki NIE znajdujące się w nawiasach kwadratowych
- [a-z] – Dopasowuje wszystkie znaki z zakresu od a do z
- [^a-z] – Dopasowuje wszystkie znaki NIE znajdujące się w zakresie od a do z
- [0-9] – Dopasowuje wszystkie znaki z zakresu od 0 do 9
- [^0-9] – Dopasowuje wszystkie znaki NIE znajdujące się w zakresie od 0 do 9
Kwantyfikatory
- x+ – Pasuje do co najmniej jednego x
- x* – Pasuje do zera lub więcej wystąpień x
- x? – Pasuje do zera lub jednego wystąpienia x
- x{n} – Pasuje do n wystąpień x
- x{n,m} – Pasuje do od n do m wystąpień x
- x{n,} – Pasuje do n lub więcej wystąpień x
Grupy
- (x) – Dopasowuje x i zapamiętuje dopasowanie
- (?\<n>x) – Dopasowuje x i oznacza je etykietą n
- (?flag:x) – Włącza flagę(y) dla x
- (?flag-flag:x) – Wyłącza flagę(y) dla x
Granice
- ^ – Dopasowuje początek ciągu znaków lub początek wiersza, jeśli ustawiona jest flaga m (wielowierszowa)
- $ – Dopasowuje koniec ciągu znaków lub koniec wiersza, jeśli ustawiona jest flaga m (wielowierszowa)
- \b – Dopasowuje początek lub koniec słowa
- \B – Dopasowuje NIE początek ani koniec słowa
- (?=...) – Dopasowuje kolejny ciąg znaków
- (?!...) – Dopasowuje NIE kolejny ciąg znaków
- (?<=...) – Dopasowuje poprzedni ciąg znaków
- (?<!...) – Dopasowuje NIE poprzedni ciąg znaków
Flagi
- /d – Wykonuje dopasowania podciągów
- /g – Wykonuje dopasowanie globalne (znajdź wszystko)
- /i – Wykonuje dopasowanie bez uwzględniania wielkości liter
- /m – Wykonuje dopasowanie wielowierszowe
- /s – Umożliwia użycie kropki (.) do dopasowywania terminatorów wiersza
- /u – Włącza obsługę Unicode
- /v – Uaktualnienie flagi /u zapewniające lepszą obsługę Unicode
- /y – Wykonuje wyszukiwanie „lepkie”
Przykłady wyrażeń regularnych z tekstem testowym
- Wyszukiwanie adresów e-mail
Wyrażenie:
/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/
Tekst testowy:
Kontakt: jan.kowalski@example.com lub support@firma123.pl
Niepoprawny: user@domain, mail@.com
- Dopasowanie dat w formacie YYYY-MM-DD
Wyrażenie:
/\b\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])\b/
Tekst testowy:
Poprawne daty: 2023-04-15, 2025-12-01
Niepoprawne: 2023-13-01, 2023-02-30
- Wyszukiwanie numerów telefonów (format PL)
Wyrażenie:
/\b\d{3}[- ]?\d{3}[- ]?\d{3}\b/
Tekst testowy:
Kontakt: 123-456-789 lub 987 654 321
Niepoprawny: 12345678, 12-345-6789
- Dopasowanie kodów pocztowych (PL)
Wyrażenie:
/\b\d{2}-\d{3}\b/
Tekst testowy:
Poprawne kody: 00-123, 87-654
Niepoprawne: 00123, 87 654
- Wyszukiwanie adresów URL
Wyrażenie:
/https?:\/\/(www\.)?[a-z0-9.-]+\.[a-z]{2,}(\/\S*)?/
Tekst testowy:
Odwiedź: https://example.com, http://www.firma.pl/test
Niepoprawne: htp://bad.url, example.com
- Dopasowanie słów zaczynających się od dużej litery
Wyrażenie:
/\b[A-Z][a-z]*\b/
Tekst testowy:
Anna Kowalska mieszka w Warszawie, a jej przyjaciel to janek. Klasy znaków
Specjalne
Kwantyfikatory
Grupy
Granice
Zestawy
Kod po stronie przeglądarki
<link type="text/css" href="http://www.dariuszrorat.ugu.pl/assets/css/bootstrap/wcag-outline.min.css" rel="stylesheet">
<style>
.max-vh-75 {
max-height: 75vh !important;
}
.editor { font-family: monospace; white-space: pre-wrap; min-height: 200px; }
.highlight { background-color: var(--bs-success-bg-subtle) !important; color: var(--bs-success-text-emphasis) !important; border-radius: 4px; padding: 0 2px; }
.error { color: #dc3545; font-weight: bold; }
.token {
display: block;
padding: 4px 6px;
border-left: 4px solid #0d6efd;
background: var(--bs-body-bg-alt);
margin-bottom: 4px;
font-family: monospace;
}
.token.group {
border-left-color: #6f42c1;
background: var(--bs-body-bg-alt);
}
.token.quantifier {
border-left-color: #20c997;
}
.token.literal {
border-left-color: #adb5bd;
}
.token-line {
display: flex;
gap: 10px;
}
.indent {
border-left: 2px dashed #ced4da;
padding-left: 12px;
margin-left: 6px;
}
</style>
<div id="app">
<!-- REGEX INPUT -->
<div class="card mb-3">
<div class="card-header"><i class="bi bi-regex"></i> Wyrażenie regularne</div>
<div class="card-body">
<div class="row g-2 align-items-center mb-2">
<div class="col-auto fs-4">/</div>
<div class="col">
<input id="pattern" class="form-control" value="\w+" aria-label="Wyrażenie regularne">
</div>
<div class="col-auto fs-4">/</div>
<div class="col-2">
<input id="flags" class="form-control" value="g" aria-label="Flagi">
</div>
</div>
<div id="error" class="alert alert-danger mb-0 d-none"></div>
</div>
</div>
<!-- REGEX BUILDER -->
<div class="card mb-3">
<div class="card-header"><i class="bi bi-bricks"></i> Regex Builder</div>
<div class="card-body">
<!-- Klasy znaków -->
<h3 class="h6">Klasy znaków</h3>
<div class="mb-2">
<button class="btn btn-outline-primary btn-sm" onclick="add('\\d')">Cyfra \d</button>
<button class="btn btn-outline-primary btn-sm" onclick="add('\\D')">Nie-cyfra \D</button>
<button class="btn btn-outline-primary btn-sm" onclick="add('\\w')">Znak \w</button>
<button class="btn btn-outline-primary btn-sm" onclick="add('\\W')">Nie-\w</button>
<button class="btn btn-outline-primary btn-sm" onclick="add('\\s')">Spacja \s</button>
<button class="btn btn-outline-primary btn-sm" onclick="add('\\S')">Nie-\s</button>
</div>
<!-- Specjalne -->
<h3 class="h6">Specjalne</h3>
<div class="mb-2">
<button class="btn btn-outline-secondary btn-sm" onclick="add('.')">Dowolny .</button>
<button class="btn btn-outline-secondary btn-sm" onclick="add('\\')">Znak \</button>
</div>
<!-- Kwantyfikatory -->
<h3 class="h6">Kwantyfikatory</h3>
<div class="mb-2">
<button class="btn btn-outline-auto-darklight btn-sm" onclick="add('+')">+</button>
<button class="btn btn-outline-auto-darklight btn-sm" onclick="add('*')">*</button>
<button class="btn btn-outline-auto-darklight btn-sm" onclick="add('?')">?</button>
<button class="btn btn-outline-auto-darklight btn-sm" onclick="wrap('{','}')">{n}</button>
<button class="btn btn-outline-auto-darklight btn-sm" onclick="wrap('{',',}')">{n,m}</button>
</div>
<!-- Grupy -->
<h3 class="h6">Grupy</h3>
<div class="mb-2">
<button class="btn btn-outline-success btn-sm" onclick="wrap('(',')')">( grupa )</button>
<button class="btn btn-outline-success btn-sm" onclick="wrap('(?:',')')">(?: grupa)</button>
<button class="btn btn-outline-success btn-sm" onclick="add('|')">| OR</button>
</div>
<!-- Granice -->
<h3 class="h6">Granice</h3>
<div class="mb-2">
<button class="btn btn-outline-danger btn-sm" onclick="add('^')">^ start</button>
<button class="btn btn-outline-danger btn-sm" onclick="add('$')">$ koniec</button>
<button class="btn btn-outline-danger btn-sm" onclick="add('\\b')">\b granica</button>
<button class="btn btn-outline-danger btn-sm" onclick="add('\\B')">\B granica</button>
</div>
<!-- Zestawy -->
<h3 class="h6">Zestawy</h3>
<div>
<button class="btn btn-outline-info btn-sm" onclick="wrap('[',']')">[abc]</button>
<button class="btn btn-outline-info btn-sm" onclick="wrap('[^',']')">[^abc]</button>
<button class="btn btn-outline-info btn-sm" onclick="wrap('[a-z]', '')">[a-z]</button>
<button class="btn btn-outline-info btn-sm" onclick="wrap('[0-9]', '')">[0-9]</button>
</div>
</div>
</div>
<!-- EXPLAIN -->
<div class="card mb-3">
<div class="card-header"><i class="bi bi-lightbulb"></i> Explain regex</div>
<div class="card-body max-vh-75 overflow-auto" id="explain"></div>
</div>
<!-- Text input -->
<div class="row">
<div class="col-md-6 mb-3">
<div class="card h-100">
<div class="card-header"><i class="bi bi-input-cursor-text"></i> Tekst wejściowy</div>
<div class="card-body">
<textarea id="inputText" class="form-control editor" rows="10" aria-label="Tekst wejściowy">
Test email: test@example.com
URL: https://example.com
Liczby: 123 456
</textarea>
</div>
</div>
</div>
<!-- Highlighted output -->
<div class="col-md-6 mb-3">
<div class="card h-100">
<div class="card-header"><i class="bi bi-highlighter"></i> Podświetlone dopasowania</div>
<div class="card-body editor" id="output"></div>
</div>
</div>
</div>
<!-- Matches -->
<div class="card">
<div class="card-header"><i class="bi bi-search"></i> Dopasowania</div>
<div class="card-body match-list max-vh-75 overflow-auto" id="matches"></div>
</div>
</div>
<script>
const patternInput = document.getElementById("pattern");
const pattern = document.getElementById("pattern");
const flagsInput = document.getElementById("flags");
const textInput = document.getElementById("inputText");
const output = document.getElementById("output");
const errorBox = document.getElementById("error");
const matchesBox = document.getElementById("matches");
const explainBox = document.getElementById("explain");
function add(val) {
const input = pattern;
const start = input.selectionStart;
const end = input.selectionEnd;
const before = input.value.substring(0, start);
const after = input.value.substring(end);
input.value = before + val + after;
// ustaw kursor za wstawioną wartością
const newPos = start + val.length;
input.setSelectionRange(newPos, newPos);
input.focus();
update();
}
function wrap(l, r) {
const input = pattern;
const start = input.selectionStart;
const end = input.selectionEnd;
const before = input.value.substring(0, start);
const selected = input.value.substring(start, end);
const after = input.value.substring(end);
input.value = before + l + selected + r + after;
// jeśli był zaznaczony tekst → zaznacz go z powrotem
if (selected.length > 0) {
input.setSelectionRange(start + l.length, start + l.length + selected.length);
} else {
// jeśli nie było zaznaczenia → kursor do środka
const pos = start + l.length;
input.setSelectionRange(pos, pos);
}
input.focus();
update();
}
function escapeHTML(str) {
return str.replace(/[&<>]/g, c => ({
'&': '&',
'<': '<',
'>': '>'
} [c]));
}
function indentStyle(level) {
return level > 0
? `style="margin-left:${level * 20}px"`
: "";
}
function explainRegex(src) {
const map = {
// === Klasy znaków ===
"\\d": {
label: "Cyfra",
description: "Dowolna cyfra od 0 do 9",
example: "\\d → 5"
},
"\\D": {
label: "Nie-cyfra",
description: "Dowolny znak, który NIE jest cyfrą",
example: "\\D → a"
},
"\\w": {
label: "Znak słowa",
description: "Litera, cyfra lub znak podkreślenia (_)",
example: "\\w → A, 7, _"
},
"\\W": {
label: "Nie-znak słowa",
description: "Dowolny znak poza literą, cyfrą i _",
example: "\\W → @"
},
"\\s": {
label: "Biały znak",
description: "Spacja, tabulator lub nowa linia",
example: "\\s → ' '"
},
"\\S": {
label: "Nie-biały znak",
description: "Dowolny znak poza białymi znakami",
example: "\\S → a"
},
// === Metaznaki ===
".": {
label: "Dowolny znak",
description: "Dowolny pojedynczy znak (poza nową linią)",
example: ". → a"
},
// === Kwantyfikatory ===
"+": {
label: "Jeden lub więcej",
description: "Poprzedni element występuje co najmniej raz",
example: "a+ → a, aaa"
},
"*": {
label: "Zero lub więcej",
description: "Poprzedni element może wystąpić dowolną liczbę razy",
example: "a* → '', aaa"
},
"?": {
label: "Opcjonalny",
description: "Poprzedni element występuje 0 lub 1 raz",
example: "a? → '', a"
},
"{n}": {
label: "Dokładnie n razy",
description: "Poprzedni element musi wystąpić dokładnie n razy",
example: "a{3} → aaa"
},
"{n,}": {
label: "Co najmniej n razy",
description: "Poprzedni element występuje n lub więcej razy",
example: "a{2,} → aa, aaa"
},
"{n,m}": {
label: "Zakres powtórzeń",
description: "Poprzedni element występuje od n do m razy",
example: "a{2,4} → aa, aaa"
},
// === Grupy i alternatywy ===
"(": {
label: "Początek grupy",
description: "Rozpoczyna grupę przechwytującą",
example: "(abc)"
},
")": {
label: "Koniec grupy",
description: "Zamyka grupę przechwytującą",
example: "(abc)"
},
"(?:": {
label: "Grupa nieprzechwytująca",
description: "Grupa używana tylko do logiki, bez zapamiętywania",
example: "(?:abc)"
},
"|": {
label: "Alternatywa (OR)",
description: "Dopasuj lewą LUB prawą stronę",
example: "a|b"
},
// === Kotwice ===
"^": {
label: "Początek tekstu",
description: "Dopasowanie musi zacząć się na początku tekstu",
example: "^abc"
},
"$": {
label: "Koniec tekstu",
description: "Dopasowanie musi zakończyć się na końcu tekstu",
example: "abc$"
},
"\\b": {
label: "Granica słowa",
description: "Początek lub koniec słowa",
example: "\\bword\\b"
},
// === Klasy znaków [] ===
"[abc]": {
label: "Zestaw znaków",
description: "Jeden z podanych znaków",
example: "[abc] → a"
},
"[^abc]": {
label: "Negacja zestawu",
description: "Dowolny znak poza podanymi",
example: "[^abc] → d"
},
// === Znaki specjalne ===
"\\.": {
label: "Kropka",
description: "Dosłowna kropka",
example: "\\. → ."
}
};
let out = "";
let groupLevel = 0;
for (let i = 0; i < src.length; i++) {
let token = src[i];
// Escaped token
if (src[i] === "\\" && src[i + 1]) {
token = src.slice(i, i + 2);
i++;
}
// === Początek grupy ===
if (token === "(") {
groupLevel++;
out += `
<div class="token group" ${indentStyle(groupLevel - 1)}>
<strong>(</strong>
<div class="text-muted">
Początek grupy <strong>#${groupLevel}</strong>
</div>
</div>`;
continue;
}
// === Koniec grupy ===
if (token === ")") {
out += `
<div class="token group" ${indentStyle(groupLevel - 1)}>
<strong>)</strong>
<div class="text-muted">
Koniec grupy <strong>#${groupLevel}</strong>
</div>
</div>`;
groupLevel--;
continue;
}
// === Zwykłe tokeny ===
const info = map[token];
const type =
["+", "*", "?", "{", "}"].includes(token)
? "quantifier"
: "literal";
out += `
<div class="token ${type}" ${indentStyle(groupLevel)}>
<div class="token-line">
<strong>${escapeHTML(token)}</strong>
<span class="text-muted">
${info ? info.label : "Znak literalny"}
</span>
</div>
${info ? `<div>${info.description}</div>` : ""}
${info?.example ? `<div class="small fst-italic">Przykład: ${info.example}</div>` : ""}
</div>`;
}
explainBox.innerHTML = out || '<div class="alert alert-warning mb-0">Brak wzorca</div>';
}
function renderMatch(match, index) {
const start = match.index;
const end = match.index + match[0].length;
let groupsHTML = "";
if (match.length > 1) {
groupsHTML = `<div class="mt-1"><strong>Grupy:</strong><ul class="mb-0">`;
for (let i = 1; i < match.length; i++) {
groupsHTML += `
<li>
<code>(${i})</code>
${match[i] !== undefined ? `"${escapeHTML(match[i])}"` : "<em>brak</em>"}
</li>`;
}
groupsHTML += `</ul></div>`;
} else {
groupsHTML = `<div class="mt-1 text-muted"><em>Brak grup przechwytujących</em></div>`;
}
return `
<div class="card mb-2">
<div class="card-body py-2">
<div class="fw-bold">Match #${index + 1}</div>
<hr class="my-2">
<div><strong>Wartość:</strong> "<code>${escapeHTML(match[0])}</code>"</div>
<div><strong>Pozycja:</strong> ${start}–${end}</div>
${groupsHTML}
</div>
</div>
`;
}
function update() {
errorBox.textContent = "";
matchesBox.innerHTML = "";
output.innerHTML = "";
explainRegex(pattern.value);
if (!errorBox.classList.contains('d-none')) {
errorBox.classList.add('d-none');
}
let regex;
try {
regex = new RegExp(patternInput.value, flagsInput.value);
} catch (e) {
errorBox.textContent = e.message;
errorBox.classList.remove('d-none');
return;
}
const text = textInput.value;
let lastIndex = 0;
let resultHTML = "";
let match;
let index = 0;
while ((match = regex.exec(text)) !== null) {
// ⛑️ ZABEZPIECZENIE PRZED PUSTYM MATCH
if (match[0] === "") {
regex.lastIndex++;
if (regex.lastIndex > text.length) break;
continue;
}
resultHTML += escapeHTML(text.slice(lastIndex, match.index));
resultHTML += `<span class="highlight">${escapeHTML(match[0])}</span>`;
matchesBox.innerHTML += renderMatch(match, index);
index++;
lastIndex = match.index + match[0].length;
if (!regex.global) break;
}
resultHTML += escapeHTML(text.slice(lastIndex));
output.innerHTML = resultHTML || escapeHTML(text);
matchesBox.innerHTML = matchesBox.innerHTML || '<div class="alert alert-warning mb-0">Brak dopasowań</div>';
}
function debounce(func, delay) {
let timer;
return function(...args) {
const context = this;
clearTimeout(timer);
timer = setTimeout(() => func.apply(context, args), delay);
};
}
pattern.oninput = flags.oninput = inputText.oninput = debounce(update, 200);
update();
</script>
Kod po stronie serwera
Brak kodu serwera
Ta aplikacja działa wyłącznie w przeglądarce i nie korzysta z kodu po stronie serwera.