Ontdek geavanceerde JavaScript patroonherkenning met reguliere expressies. Leer over regex-syntaxis, praktische toepassingen en optimalisatietechnieken voor efficiënte en robuuste code.
JavaScript Patroonherkenning met Reguliere Expressies: Een Uitgebreide Gids
Reguliere expressies (regex) zijn een krachtig hulpmiddel voor patroonherkenning en tekstmanipulatie in JavaScript. Ze stellen ontwikkelaars in staat om strings te doorzoeken, te valideren en te transformeren op basis van gedefinieerde patronen. Deze gids biedt een uitgebreid overzicht van reguliere expressies in JavaScript, inclusief syntaxis, gebruik en geavanceerde technieken.
Wat zijn Reguliere Expressies?
Een reguliere expressie is een reeks tekens die een zoekpatroon definiëren. Deze patronen worden gebruikt om strings te matchen en te manipuleren. Reguliere expressies worden veel gebruikt in programmeren voor taken zoals:
- Datavalidatie: Zorgen dat gebruikersinvoer voldoet aan specifieke formaten (bijv. e-mailadressen, telefoonnummers).
- Data-extractie: Specifieke informatie uit tekst halen (bijv. datums, URL's of prijzen extraheren).
- Zoeken en Vervangen: Tekst zoeken en vervangen op basis van complexe patronen.
- Tekstverwerking: Strings splitsen, samenvoegen of transformeren op basis van gedefinieerde regels.
Reguliere Expressies Maken in JavaScript
In JavaScript kunnen reguliere expressies op twee manieren worden gemaakt:
- Met een Reguliere Expressie Literal: Plaats het patroon tussen schuine strepen (
/). - Met de
RegExpConstructor: Maak eenRegExp-object aan met het patroon als een string.
Voorbeeld:
// Met een reguliere expressie literal
const regexLiteral = /hello/;
// Met de RegExp constructor
const regexConstructor = new RegExp("hello");
De keuze tussen de twee methoden hangt af van of het patroon bekend is tijdens het compileren of dynamisch wordt gegenereerd. Gebruik de literal notatie wanneer het patroon vastligt en van tevoren bekend is. Gebruik de constructor wanneer het patroon programmatisch moet worden opgebouwd, vooral bij het gebruik van variabelen.
Basis Regex Syntaxis
Reguliere expressies bestaan uit tekens die het te matchen patroon vertegenwoordigen. Hier zijn enkele fundamentele regex-componenten:
- Letterlijke Tekens: Matchen de tekens zelf (bijv.
/a/matcht het teken 'a'). - Metatekens: Hebben speciale betekenissen (bijv.
.,^,$,*,+,?,[],{},(),\,|). - Tekenklassen: Vertegenwoordigen verzamelingen van tekens (bijv.
[abc]matcht 'a', 'b' of 'c'). - Kwantificeerders: Specificeren hoe vaak een teken of groep moet voorkomen (bijv.
*,+,?,{n},{n,},{n,m}). - Ankers: Matchen posities in de string (bijv.
^matcht het begin,$matcht het einde).
Veelvoorkomende Metatekens:
.(punt): Matcht elk enkel teken behalve een newline.^(caret/dakje): Matcht het begin van de string.$(dollar): Matcht het einde van de string.*(asterisk/sterretje): Matcht nul of meer voorkomens van het voorgaande teken of groep.+(plus): Matcht één of meer voorkomens van het voorgaande teken of groep.?(vraagteken): Matcht nul of één voorkomen van het voorgaande teken of groep. Gebruikt voor optionele tekens.[](vierkante haken): Definieert een tekenklasse, matcht elk enkel teken binnen de haken.{}(accolades): Specificeert het aantal voorkomens dat moet worden gematcht.{n}matcht exact n keer,{n,}matcht n of meer keer,{n,m}matcht tussen n en m keer.()(haakjes): Groepeert tekens en legt de gematchte substring vast.\(backslash): Escapet metatekens, zodat je ze letterlijk kunt matchen.|(pipe): Werkt als een "of"-operator, matcht de expressie ervoor of erna.
Tekenklassen:
[abc]: Matcht een van de tekens a, b of c.[^abc]: Matcht elk teken dat *geen* a, b of c is.[a-z]: Matcht elke kleine letter van a tot z.[A-Z]: Matcht elke hoofdletter van A tot Z.[0-9]: Matcht elk cijfer van 0 tot 9.[a-zA-Z0-9]: Matcht elk alfanumeriek teken.\d: Matcht elk cijfer (equivalent aan[0-9]).\D: Matcht elk niet-cijfer teken (equivalent aan[^0-9]).\w: Matcht elk woordteken (alfanumeriek plus underscore; equivalent aan[a-zA-Z0-9_]).\W: Matcht elk niet-woordteken (equivalent aan[^a-zA-Z0-9_]).\s: Matcht elk witruimteteken (spatie, tab, newline, etc.).\S: Matcht elk niet-witruimteteken.
Kwantificeerders:
*: Matcht het voorgaande element nul of meer keer. Bijvoorbeeld,a*matcht "", "a", "aa", "aaa", enzovoort.+: Matcht het voorgaande element één of meer keer. Bijvoorbeeld,a+matcht "a", "aa", "aaa", maar niet "".?: Matcht het voorgaande element nul of één keer. Bijvoorbeeld,a?matcht "" of "a".{n}: Matcht het voorgaande element exact *n* keer. Bijvoorbeeld,a{3}matcht "aaa".{n,}: Matcht het voorgaande element *n* of meer keer. Bijvoorbeeld,a{2,}matcht "aa", "aaa", "aaaa", enzovoort.{n,m}: Matcht het voorgaande element tussen *n* en *m* keer (inclusief). Bijvoorbeeld,a{2,4}matcht "aa", "aaa", of "aaaa".
Ankers:
^: Matcht het begin van de string. Bijvoorbeeld,^Hellomatcht strings die *beginnen* met "Hello".$: Matcht het einde van de string. Bijvoorbeeld,World$matcht strings die *eindigen* met "World".\b: Matcht een woordgrens. Dit is de positie tussen een woordteken (\w) en een niet-woordteken (\W) of het begin of einde van de string. Bijvoorbeeld,\bword\bmatcht het hele woord "word".
Flags:
Regex flags passen het gedrag van reguliere expressies aan. Ze worden toegevoegd aan het einde van de regex literal of als tweede argument doorgegeven aan de RegExp constructor.
g(global): Matcht alle voorkomens van het patroon, niet alleen de eerste.i(ignore case): Voert een hoofdletterongevoelige matching uit.m(multiline): Schakelt de multiline-modus in, waarbij^en$het begin en einde van elke regel (gescheiden door\n) matchen.s(dotAll): Staat de punt (.) toe om ook newline-tekens te matchen.u(unicode): Schakelt volledige Unicode-ondersteuning in.y(sticky): Matcht alleen vanaf de index die wordt aangegeven door delastIndexeigenschap van de regex.
JavaScript Regex Methoden
JavaScript biedt verschillende methoden om met reguliere expressies te werken:
test(): Test of een string overeenkomt met het patroon. Geefttrueoffalseterug.exec(): Voert een zoekopdracht uit voor een match in een string. Geeft een array terug met de gematchte tekst en vastgelegde groepen, ofnullals er geen match wordt gevonden.match(): Geeft een array terug met de resultaten van het matchen van een string met een reguliere expressie. Gedraagt zich anders met en zonder degflag.search(): Test op een match in een string. Geeft de index van de eerste match terug, of -1 als er geen match wordt gevonden.replace(): Vervangt voorkomens van een patroon door een vervangende string of een functie die de vervangende string retourneert.split(): Splitst een string in een array van substrings op basis van een reguliere expressie.
Voorbeelden van Regex Methoden:
// test()
const regex = /hello/;
const str = "hello world";
console.log(regex.test(str)); // Output: true
// exec()
const regex2 = /hello (\w+)/;
const str2 = "hello world";
const result = regex2.exec(str2);
console.log(result); // Output: ["hello world", "world", index: 0, input: "hello world", groups: undefined]
// match() met 'g' flag
const regex3 = /\d+/g; // Matcht één of meer cijfers globaal
const str3 = "Er zijn 123 appels en 456 sinaasappels.";
const matches = str3.match(regex3);
console.log(matches); // Output: ["123", "456"]
// match() zonder 'g' flag
const regex4 = /\d+/;
const str4 = "Er zijn 123 appels en 456 sinaasappels.";
const match = str4.match(regex4);
console.log(match); // Output: ["123", index: 8, input: "Er zijn 123 appels en 456 sinaasappels.", groups: undefined]
// search()
const regex5 = /world/;
const str5 = "hello world";
console.log(str5.search(regex5)); // Output: 6
// replace()
const regex6 = /world/;
const str6 = "hello world";
const newStr = str6.replace(regex6, "JavaScript");
console.log(newStr); // Output: hello JavaScript
// replace() met een functie
const regex7 = /(\d+)-(\d+)-(\d+)/;
const str7 = "De datum van vandaag is 2023-10-27";
const newStr2 = str7.replace(regex7, (match, year, month, day) => {
return `${day}/${month}/${year}`;
});
console.log(newStr2); // Output: De datum van vandaag is 27/10/2023
// split()
const regex8 = /, /;
const str8 = "appel, banaan, kers";
const arr = str8.split(regex8);
console.log(arr); // Output: ["appel", "banaan", "kers"]
Geavanceerde Regex Technieken
Vastleggende Groepen (Capturing Groups):
Haakjes () worden gebruikt om vastleggende groepen in reguliere expressies te maken. Vastgelegde groepen stellen u in staat om specifieke delen van de gematchte tekst te extraheren. De exec() en match() methoden retourneren een array waarbij het eerste element de volledige match is, en de volgende elementen de vastgelegde groepen zijn.
const regex = /(\d{4})-(\d{2})-(\d{2})/;
const dateString = "2023-10-27";
const match = regex.exec(dateString);
console.log(match[0]); // Output: 2023-10-27 (De volledige match)
console.log(match[1]); // Output: 2023 (De eerste vastgelegde groep - jaar)
console.log(match[2]); // Output: 10 (De tweede vastgelegde groep - maand)
console.log(match[3]); // Output: 27 (De derde vastgelegde groep - dag)
Benoemde Vastleggende Groepen (Named Capturing Groups):
ES2018 introduceerde benoemde vastleggende groepen, waarmee u namen kunt toewijzen aan vastleggende groepen met de syntaxis (?. Dit maakt de code leesbaarder en beter onderhoudbaar.
const regex = /(?\d{4})-(?\d{2})-(?\d{2})/;
const dateString = "2023-10-27";
const match = regex.exec(dateString);
console.log(match.groups.year); // Output: 2023
console.log(match.groups.month); // Output: 10
console.log(match.groups.day); // Output: 27
Niet-Vastleggende Groepen (Non-Capturing Groups):
Als u delen van een regex moet groeperen zonder ze vast te leggen (bijv. om een kwantificeerder op een groep toe te passen), kunt u een niet-vastleggende groep gebruiken met de syntaxis (?:...). Dit voorkomt onnodige geheugentoewijzing voor vastgelegde groepen.
const regex = /(?:https?:\/\/)?([\w\.]+)/; // Matcht een URL maar legt alleen de domeinnaam vast
const url = "https://www.example.com/path";
const match = regex.exec(url);
console.log(match[1]); // Output: www.example.com
Lookarounds:
Lookarounds zijn zero-width assertions die een positie in een string matchen op basis van een patroon dat die positie voorafgaat (lookbehind) of volgt (lookahead), zonder het lookaround-patroon zelf in de match op te nemen.
- Positive Lookahead:
(?=...)Matcht als het patroon binnen de lookahead de huidige positie *volgt*. - Negative Lookahead:
(?!...)Matcht als het patroon binnen de lookahead de huidige positie *niet* volgt. - Positive Lookbehind:
(?<=...)Matcht als het patroon binnen de lookbehind de huidige positie *voorafgaat*. - Negative Lookbehind:
(? Matcht als het patroon binnen de lookbehind de huidige positie *niet* voorafgaat.
Voorbeeld:
// Positive Lookahead: Krijg de prijs alleen wanneer gevolgd door USD
const regex = /\d+(?= USD)/;
const text = "De prijs is 100 USD";
const match = text.match(regex);
console.log(match); // Output: ["100"]
// Negative Lookahead: Krijg het woord alleen wanneer niet gevolgd door een getal
const regex2 = /\b\w+\b(?! \d)/;
const text2 = "appel 123 banaan sinaasappel 456";
const matches = text2.match(regex2);
console.log(matches); // Output: null omdat match() alleen de eerste match retourneert zonder 'g' flag, wat niet is wat we nodig hebben.
// om dit op te lossen:
const regex3 = /\b\w+\b(?! \d)/g;
const text3 = "appel 123 banaan sinaasappel 456";
const matches3 = text3.match(regex3);
console.log(matches3); // Output: [ 'banaan' ]
// Positive Lookbehind: Krijg de waarde alleen wanneer voorafgegaan door $
const regex4 = /(?<=\$)\d+/;
const text4 = "De prijs is $200";
const match4 = text4.match(regex4);
console.log(match4); // Output: ["200"]
// Negative Lookbehind: Krijg het woord alleen wanneer niet voorafgegaan door het woord 'niet'
const regex5 = /(?
Terugverwijzingen (Backreferences):
Terugverwijzingen stellen u in staat om te verwijzen naar eerder vastgelegde groepen binnen dezelfde reguliere expressie. Ze gebruiken de syntaxis \1, \2, enz., waarbij het getal overeenkomt met het nummer van de vastgelegde groep.
const regex = /([a-z]+) \1/;
const text = "hallo hallo wereld";
const match = regex.exec(text);
console.log(match); // Output: ["hallo hallo", "hallo", index: 0, input: "hallo hallo wereld", groups: undefined]
Praktische Toepassingen van Reguliere Expressies
E-mailadressen Valideren:
Een veelvoorkomend gebruik van reguliere expressies is het valideren van e-mailadressen. Hoewel een perfecte e-mailvalidatie-regex extreem complex is, is hier een vereenvoudigd voorbeeld:
const emailRegex = /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/;
console.log(emailRegex.test("test@example.com")); // Output: true
console.log(emailRegex.test("ongeldig-email")); // Output: false
console.log(emailRegex.test("test@sub.example.co.uk")); // Output: true
URL's uit Tekst Extraheren:
U kunt reguliere expressies gebruiken om URL's uit een blok tekst te extraheren:
const urlRegex = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/g;
const text = "Bezoek onze website op https://www.example.com of bekijk http://blog.example.org.";
const urls = text.match(urlRegex);
console.log(urls); // Output: ["https://www.example.com", "http://blog.example.org"]
CSV-data Parsen:
Reguliere expressies kunnen worden gebruikt om CSV-data (Comma-Separated Values) te parsen. Hier is een voorbeeld van het splitsen van een CSV-string in een array van waarden, waarbij rekening wordt gehouden met velden tussen aanhalingstekens:
const csvString = 'Jan,Jansen,"Hoofdstraat 123",Amsterdam';
const csvRegex = /(?:"([^"]*(?:""[^"]*)*)")|([^,]+)/g; //Gecorrigeerde CSV regex
let values = [];
let match;
while (match = csvRegex.exec(csvString)) {
values.push(match[1] ? match[1].replace(/""/g, '"') : match[2]);
}
console.log(values); // Output: ["Jan", "Jansen", "Hoofdstraat 123", "Amsterdam"]
Internationale Telefoonnummers Valideren
Het valideren van internationale telefoonnummers is complex vanwege variërende formaten en lengtes. Een robuuste oplossing omvat vaak het gebruik van een bibliotheek, maar een vereenvoudigde regex kan basisvalidatie bieden:
const phoneRegex = /^\+(?:[0-9] ?){6,14}[0-9]$/;
console.log(phoneRegex.test("+1 555 123 4567")); // Output: true (VS Voorbeeld)
console.log(phoneRegex.test("+44 20 7946 0500")); // Output: true (VK Voorbeeld)
console.log(phoneRegex.test("+81 3 3224 5000")); // Output: true (Japan Voorbeeld)
console.log(phoneRegex.test("06-12345678")); // Output: false
Wachtwoordsterkte Valideren
Reguliere expressies zijn nuttig voor het afdwingen van beleid voor wachtwoordsterkte. Het onderstaande voorbeeld controleert op minimale lengte, hoofdletters, kleine letters en een cijfer.
const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$/;
console.log(passwordRegex.test("W@chtwoord123")); // Output: true
console.log(passwordRegex.test("wachtwoord")); // Output: false (geen hoofdletter of cijfer)
console.log(passwordRegex.test("Wachtwoord")); // Output: false (geen cijfer)
console.log(passwordRegex.test("Wacht123")); // Output: false (geen kleine letter)
console.log(passwordRegex.test("W@cht1")); // Output: false (minder dan 8 tekens)
Regex Optimalisatietechnieken
Reguliere expressies kunnen rekenkundig intensief zijn, vooral bij complexe patronen of grote inputs. Hier zijn enkele technieken om de prestaties van regex te optimaliseren:
- Wees Specifiek: Vermijd het gebruik van te algemene patronen die meer kunnen matchen dan de bedoeling is.
- Gebruik Ankers: Veranker de regex waar mogelijk aan het begin of einde van de string (
^,$). - Vermijd Backtracking: Minimaliseer backtracking door possessive quantifiers (bijv.
++in plaats van+) of atomic groups ((?>...)) te gebruiken waar van toepassing. - Compileer Eenmaal: Als u dezelfde regex meerdere keren gebruikt, compileer deze dan één keer en hergebruik het
RegExp-object. - Gebruik Tekenklassen Slim: Tekenklassen (
[]) zijn over het algemeen sneller dan alternaties (|). - Houd het Simpel: Vermijd te complexe regexen die moeilijk te begrijpen en te onderhouden zijn. Soms kan het efficiënter zijn om een complexe taak op te splitsen in meerdere eenvoudigere regexen of andere stringmanipulatietechnieken te gebruiken.
Veelgemaakte Regex Fouten
- Vergeten Metatekens te Escapen: Het niet escapen van speciale tekens zoals
.,*,+,?,$,^,(,),[,],{,},|, en\wanneer u ze letterlijk wilt matchen. - Overmatig Gebruik van
.(punt): De punt matcht elk teken (behalve newline in sommige modi), wat kan leiden tot onverwachte matches als het niet zorgvuldig wordt gebruikt. Wees specifieker waar mogelijk met tekenklassen of andere meer beperkende patronen. - Greediness (Gretigheid): Standaard zijn kwantificeerders zoals
*en+'greedy' en matchen ze zoveel mogelijk. Gebruik 'lazy' kwantificeerders (*?,+?) wanneer u de kortst mogelijke string moet matchen. - Onjuist Gebruik van Ankers: Het verkeerd begrijpen van het gedrag van
^(begin van string/regel) en$(einde van string/regel) kan leiden tot onjuiste matching. Vergeet niet dem(multiline) flag te gebruiken wanneer u met multiline strings werkt en wilt dat^en$het begin en einde van elke regel matchen. - Geen Rekening Houden met Randgevallen: Het niet overwegen van alle mogelijke invoerscenario's en randgevallen kan tot bugs leiden. Test uw regexen grondig met een verscheidenheid aan inputs, inclusief lege strings, ongeldige tekens en grensvoorwaarden.
- Prestatieproblemen: Het construeren van te complexe en inefficiënte regexen kan prestatieproblemen veroorzaken, vooral bij grote inputs. Optimaliseer uw regexen door specifiekere patronen te gebruiken, onnodige backtracking te vermijden en regexen die herhaaldelijk worden gebruikt te compileren.
- Tekencodering Negeren: Het niet correct omgaan met tekencoderingen (vooral Unicode) kan leiden tot onverwachte resultaten. Gebruik de
uflag wanneer u met Unicode-tekens werkt om een correcte matching te garanderen.
Conclusie
Reguliere expressies zijn een waardevol hulpmiddel voor patroonherkenning en tekstmanipulatie in JavaScript. Het beheersen van de regex-syntaxis en -technieken stelt u in staat om een breed scala aan problemen efficiënt op te lossen, van datavalidatie tot complexe tekstverwerking. Door de concepten in deze gids te begrijpen en te oefenen met praktijkvoorbeelden, kunt u bedreven worden in het gebruik van reguliere expressies om uw JavaScript-ontwikkelingsvaardigheden te verbeteren.
Onthoud dat reguliere expressies complex kunnen zijn, en het is vaak nuttig om ze grondig te testen met online regex-testers zoals regex101.com of regexr.com. Dit stelt u in staat om de matches te visualiseren en eventuele problemen effectief op te lossen. Veel codeerplezier!