Przejdź do głównej treści

Regex Builder

Grafika Regex

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

  1. 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  
  1. 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  
  1. 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  
  1. 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  
  1. 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  
  1. 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.  
Wyrażenie regularne
/
/
Regex Builder

Klasy znaków

Specjalne

Kwantyfikatory

Grupy

Granice

Zestawy

Explain regex
Tekst wejściowy
Podświetlone dopasowania
Dopasowania

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 => ({
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;'
  } [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.

19 grudnia 2025 2

Kategorie

Technologie

Dziękujemy!
()

Informacja o cookies

Moja strona internetowa wykorzystuje wyłącznie niezbędne pliki cookies, które są wymagane do jej prawidłowego działania. Nie używam ciasteczek w celach marketingowych ani analitycznych. Korzystając z mojej strony, wyrażasz zgodę na stosowanie tych plików. Możesz dowiedzieć się więcej w mojej polityce prywatności.