<KodLexikon/>
Illustration för javascript-programmering
← Alla artiklar
javascript11 min läsning2026-09-10

Regex i JavaScript: Metoder, flaggor och catastrophic backtracking

test(), match(), matchAll() och replace() - när du använder vilken. Namngivna grupper, escaping av dynamiska mönster, och regexet som kan frysa din server på fientlig indata.

Jeff Atwoods gamla citat — "Some people, when confronted with a problem, think 'I know, I’ll use regular expressions.' Now they have two problems." — cirkulerar fortfarande i utvecklarcommunityn, och av goda skäl. Regex i JavaScript är ett av de kraftfullaste verktygen för textmatchning som finns, men det är också det verktyg som oftast skrivs fel, testas för lite, och lämnas okommenterat tills någon annan måste felsöka en tätt hopskriven rad regex-tecken utan en enda förklarande kommentar. Den här guiden går igenom hur regex faktiskt fungerar i JavaScript, vilka metoder du ska använda när, och fällorna som skapar de mest svårhittade buggarna.

Skapa ett regex — två sätt, olika användningsfall

// Literal syntax — kompileras vid parse-tid, snabbast för statiska mönster
const mönster = /\d{3}-\d{4}/;

// RegExp-konstruktor — nödvändig när mönstret byggs dynamiskt från en variabel
const sökord = "kod.lexikon";
const dynamiskt = new RegExp(escapeRegex(sökord));
// OBS: escapa alltid specialtecken i användarinmatning innan den blir del
// av ett mönster — annars kan indata som "a.*" tolkas som regex-syntax
// istället för bokstavlig text (se avsnittet om escaping längre ner)

De flaggor du faktiskt använder

/mönster/g   // global — hitta ALLA matchningar, inte bara den första
/mönster/i   // ignorera versaler/gemener
/mönster/m   // multiline — ^ och $ matchar radbörjan/radslut, inte bara hela strängen
/mönster/s   // dotAll — . matchar även radbrytningar
/mönster/u   // unicode — korrekt hantering av emoji och tecken utanför BMP

// Kombinera fritt:
const alla = /fel/gi;

Vanlig fälla: g-flaggan gör att regex.test() och regex.exec() kommer ihåg var de senast matchade via lastIndex. Återanvänder du samma regex-objekt i en loop utan att återställa lastIndex, hoppar nästa anrop över matchningar den redan passerat — eller returnerar false växelvis med true på exakt samma indata.

const regex = /kod/g;
console.log(regex.test("kodlexikon"));  // true, lastIndex flyttas till 3
console.log(regex.test("kodlexikon"));  // false! sökningen börjar nu från index 3

// Fix: skapa ett nytt regex-objekt varje gång, eller nollställ manuellt
regex.lastIndex = 0;

De fyra metoderna — och när du använder vilken

const text = "Kontakt: erik@exempel.se eller lisa@exempel.se";
const epostMönster = /[\w.+-]+@[\w-]+\.[a-z]{2,}/gi;

// .test() — bara ja/nej, snabbast om du inte behöver matchningen
epostMönster.test(text);  // true

// .match() — utan /g: detaljer om FÖRSTA matchningen (grupper, index)
// med /g: array av ALLA matchade strängar, ingen gruppinfo
text.match(epostMönster);  // ["erik@exempel.se", "lisa@exempel.se"]

// .matchAll() — iterator med FULL detalj för varje matchning, kräver /g
for (const m of text.matchAll(epostMönster)) {
  console.log(m[0], "vid index", m.index);
}

// .replace() — med en funktion som andra argument för logik per match
text.replace(epostMönster, (match) => match.split("@")[0] + "@***");
// → "Kontakt: erik@*** eller lisa@***"

Fångstgrupper och namngivna grupper

// Numrerade grupper — funkar, men blir oläsligt med fler än två-tre grupper
const datum = /(\d{4})-(\d{2})-(\d{2})/;
const [, år, månad, dag] = "2026-09-10".match(datum);

// Namngivna grupper — samma funktionalitet, läsbart resultat
const datumNamngiven = /(?<år>\d{4})-(?<månad>\d{2})-(?<dag>\d{2})/;
const match = "2026-09-10".match(datumNamngiven);
console.log(match.groups.år);     // "2026"
console.log(match.groups.månad);  // "09"

// Fungerar även i .replace() med $<namn>
"2026-09-10".replace(datumNamngiven, "$<dag>/$<månad>/$<år>");
// → "10/09/2026"

Escapa specialtecken i dynamiska mönster

Bygger du ett mönster från indata du inte kontrollerar — ett sökord från en användare, ett filnamn, en URL-parameter — måste specialtecken som . * + ? ^ $ { } ( ) | [ ] och bakstreck escapas innan de blir del av regexet. Annars kan indata som "a.*" tolkas som regex-syntax istället för bokstavlig text.

function escapeRegex(str) {
  return str.replace(/[.*+?^${}()|[\]\\]/g, (tecken) => "\\" + tecken);
}

escapeRegex("kod.lexikon");  // "kod\.lexikon" — punkten matchar nu bara punkt,
                              // inte "vilket tecken som helst"

Catastrophic backtracking — regexet som fryser din server

Det här är den farligaste fällan, och den som faktiskt orsakat produktionsincidenter (ReDoS — Regular Expression Denial of Service). Vissa mönster med nästlad upprepning kan få motorn att testa exponentiellt många kombinationer på viss indata.

// ❌ Farligt mönster — nästlad upprepning av liknande tecken
const farligt = /^(a+)+$/;

// På "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!"
// kan detta ta SEKUNDER eller MINUTER — motorn provar varenda uppdelning
// av a-tecknen innan den ger upp på "!"

// ✅ Skriv om utan nästlad kvantifierare — samma matchning, ingen backtracking-explosion
const säkert = /^a+$/;

// Regel: undvik mönster där en grupp med upprepning (+  eller *)
// innehåller en annan grupp med upprepning som matchar överlappande tecken

Validerar du indata från användare — e-post, filnamn, URL:er — testa alltid mönstret mot lång, "nästan matchande" indata innan det går till produktion. Verktyg som safe-regex kan flagga riskabla mönster automatiskt i CI.

Läsbarhet: extrahera och kommentera komplexa mönster

// ❌ Oläsligt utan sammanhang
const check = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;

// ✅ Namngivet, med kommentar om vad varje del gör
// E-postvalidering: användarnamn@domän.tld
// - användarnamn: bokstäver, siffror, . _ % + -
// - domän: bokstäver, siffror, . -
// - tld: minst 2 bokstäver
const EPOST_MÖNSTER = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;

function ärGiltigEpost(värde) {
  return EPOST_MÖNSTER.test(värde);
}

För riktigt komplexa mönster: överväg om ett litet valideringsbibliotek (t.ex. Zod för scheman) gör koden mer underhållbar än ett enda tätt regex. Regex vinner på prestanda och inga beroenden — inte alltid på läsbarhet.

Checklista innan du committar ett regex

  • Testa med tom sträng, extremt lång sträng och specialtecken — inte bara "det vanliga fallet".
  • Kolla efter nästlad upprepning som kan orsaka catastrophic backtracking på fientlig indata.
  • Escapa alltid användarinmatning innan den blir del av ett dynamiskt mönster.
  • Nollställ lastIndex eller skapa ett nytt regex-objekt om du återanvänder ett globalt mönster i en loop.
  • Namnge komplexa grupper istället för att förlita dig på numrerade index.

Nordisk vinkel: regex i validering av svenska format

Svenska personnummer, postnummer och telefonnummer har egna format som ofta valideras med regex i svenska webbappar — men fälls i samma mönster som allt annat: för strikta mönster som avvisar giltiga indata (personnummer med eller utan bindestreck, med eller utan sekelsiffror), eller för löst skrivna mönster som accepterar felaktig data. Testa alltid mot verkliga exempel, inte bara det format du själv skrev mönstret utifrån.

Källor och vidare läsning

  1. MDN — Regular expressions
    Komplett guide till syntax, flaggor och motorns beteende i JavaScript.
    developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions
  2. MDN — RegExp-referens
    Fullständig API-referens för RegExp-objektet: metoder, egenskaper och exempel.
    developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp