Reguliere expressie elke tekenreeks. Een praktische introductie tot reguliere expressies voor beginners

Regex is een gemakkelijke en leuke introductie tot de theorie van reguliere expressies van webontwikkelaar Josh Hawkins en behandelt alle basisprincipes die een beginner moet kennen.

Heb jij ooit met snaren gewerkt? Ja, ja, met diezelfde ‘karakterarrays’ die we allemaal kennen en waar we van houden. Als je iets anders dan pure C hebt geprogrammeerd, kun je veilig aannemen dat dit het geval is, en meer dan eens. Maar wat als je met veel snaren te maken hebt? Of met strings die niet door uw programma zijn gegenereerd? Je leest bijvoorbeeld e-mail, ontleed de argumenten opdrachtregel of het lezen van instructies die door een persoon zijn geschreven en een meer gestructureerde methode nodig hebben om ermee te werken.

Natuurlijk kunt u elk woord of teken in alle regels herhalen. En dergelijke code zal waarschijnlijk vrij eenvoudig te begrijpen zijn. Maar bij grootschalige toepassingen kan dit onnodig omslachtig en te arbeidsintensief zijn.

Invoering. Reguliere expressie

Laten we, zonder in de jungle van de diepgaande computerwetenschap te duiken, een reguliere expressie definiëren.

  • Reguliere expressies zijn regels die een formele taal beschrijven.
  • Reguliere expressies zijn een soort formele taal die door een toestandsmachine kan worden verwerkt.

Er zijn veel andere definities van reguliere expressies, dus als het bovenstaande niet genoeg is om je blij te maken, kun je een paar minuten besteden aan Googlen.

Invoering. Regex

Nu komen we misschien op het punt waarop het tijd is om bang te worden (als je dat nog niet hebt gedaan). We zullen kijken naar de verschillen tussen wat er in het concept van reguliere expressies in programmeertalen zit, en wat er in de fundamentele informatica zit.

  • Reguliere expressies zijn vanuit het oogpunt van de informatica regels die een formele taal verklaren.
  • Reguliere expressies vanuit het oogpunt van programmeertalen zijn een grammatica die sommige in grotere mate uitdrukt contextgevoelige taal.

Contextgevoelige talen zijn aanzienlijk complexer en krachtiger, dus van nu af aan zullen we afspreken om reguliere expressies in programmeertaaltermen ‘regex’ te noemen om hun isolatie van formele talen algemeen.

Regex leren schrijven

Reguliere expressies worden beschreven met twee schuine strepen ( // ) en zoek naar tekenreeksen die overeenkomen met het patroon daartussen. Bijvoorbeeld, /Hoi/ komt overeen met "Hallo", zodat we kunnen controleren of een tekenreeks met dit patroon overeenkomt.

Symbolen erin reguliere expressies worden vergeleken in de volgorde waarin ze worden ingevoerd. Dus /Hallo wereld/ reageert op de string “Hallo wereld”.

Je kunt het zoeken naar willekeurige woorden eenvoudiger maken door een beetje regex-magie toe te voegen: \w komt overeen met elk “woord” dat alleen uit letters bestaat. Getallen worden geïdentificeerd volgens hetzelfde principe: \D .

Voorbeeld 1

Mooi, nu kunnen we snaren vergelijken of controleren of ze in een bepaald patroon passen. Wat is het volgende? Kunnen reguliere expressies nog andere functies uitvoeren?

Wees gerust! Laten we zeggen dat we een IRC-chatbot hebben geschreven die reageert als iemand "Josh" schrijft. Onze bot scant elk bericht totdat hij een match vindt. Dan antwoordt de bot: “Woah, ik hoop dat je niet slecht praat over mijn vriend Josh!” (“Oh, ik hoop dat je niet slecht praat over mijn vriend Josh!”). Omdat alleen robots vrienden zijn met de Joshes.

Onze bot gebruikt een sjabloon om strings te vergelijken /Josh/ . Op een gegeven moment zal iemand genaamd Eli zeggen: "Eli: Josh, heb je echt zoveel cafeïne nodig?" Onze bot spitst zijn oren, detecteert een match en geeft een onverwacht antwoord, wat Eli voldoende bang zal maken. Missie volbracht! Of niet?

Wat als onze bot slimmer was? Wat als hij bijvoorbeeld de spreker bij naam aansprak? Iets als "Woah, ik hoop dat je mijn vriend Josh, Eli niet kwaad maakt."

Kwantificatoren (herhalende tekens)

0 of meer

We kunnen dit doen... Maar eerst moeten we een paar dingen begrijpen. Eerst - kwantoren(voor herhalende tekens). Kan worden gebruikt * om 0 of meer tekens erna aan te geven. Bijvoorbeeld, /A*/ kan zowel "aaaaaa" als "" matchen. Ja, je hebt het goed gehoord: het reageert op een lege string.

* dient om iets optioneels aan te duiden, aangezien het symbool waarmee het correspondeert helemaal niet hoeft te bestaan. Maar hij kan het. En meer dan eens (theoretisch ontelbare keren).
U kunt “Josh” aanduiden met /Josh/ , maar we kunnen ook “Jjjjjjjjjosh” of “osh” opgeven bij het patroon /J*osh/ .

1 of meer

Er wordt gebruik gemaakt van een of meer tekens + . Het werkt effectief volgens hetzelfde principe als * , behalve dat het bestaan ​​van ten minste één teken niet langer optioneel is: het moet aanwezig zijn ten minste een.

We kunnen dus de sjabloon instellen /J+osh/ de tekenreeksen "Josh" of "Jjjjjjjjjosh", maar niet "osh".

Metakarakters

Geweldig, we hebben onze handen al op veel manieren bevrijd. Misschien roept iemand op dit moment 'Joooooosh' als hij of zij al boos genoeg is...

Maar wat als hij zo boos wordt dat hij zelfs een paar keer met zijn gezicht tegen het toetsenbord slaat? Hoe duiden we “aaavyopshadlorvpt” aan zonder van tevoren te weten hoe nauwkeurig zijn neus is?
Door te gebruiken metatekens!

Met metatekens kunt u absoluut ALLES specificeren. Hun syntaxis is . . (Ja, punt. Gewoon een punt.). We wedden dat je het veel gebruikt, dus voel je vrij om het te gebruiken om het einde van een zin te markeren.

U kunt “Joooafhuaisggsh” instellen met de uitdrukking /Jo+.*sh/ , waarbij eerder verworven kennis over herhalende karakters en metatekens wordt gecombineerd. Om precies te zijn: deze uitdrukking komt overeen met één "J", één of meer "o", nul of meer metatekens, en één "s" en één "h". Deze vijf blokken leiden ons naar wat wij noemen...

...groepen karakters

Karaktergroepen- dit zijn karakterblokken waarbij de volgorde van de componenten belangrijk is. Ze worden als één geheel beschouwd. Gebruiken * of + , specificeert u feitelijk een reeks van een herhalende groep tekens, en niet alleen het laatste teken.

Dit is handig om te begrijpen als een op zichzelf staande techniek, maar krijgt meer functionaliteit in combinatie met herhalende symbolen. Groepen tekens worden gespecificeerd met behulp van haakjes (ja, die jongens).
Laten we zeggen dat we 'Jos' willen herhalen, maar niet 'h'. zoiets als "JosJosJosJosJosh". Dit kan gedaan worden met de uitdrukking /(Jos)+h/ . Eenvoudig, nietwaar?

Maar tot slot... Terugkomend op ons eerste voorbeeld: hoe halen we Eli's naam in onze IRC-chat uit het bericht dat ze heeft verzonden?

Groepen karakters kunnen ook dienen om substrings te onthouden. Om dit te doen doen ze meestal zoiets als \1 om de eerste gespecificeerde groep te bepalen.

Bijvoorbeeld, /(.+) \1/ speciaal geval. Hier zien we een set willekeurige symbolen, een of meerdere keren herhaald, een spatie erna, en dan exact dezelfde set opnieuw herhalen. Een dergelijke uitdrukking komt dus overeen met 'abc abc', maar niet met 'abc def', ook al komt 'def' zelf overeen (.*) .

Het onthouden van wedstrijden is een heel krachtig iets, en het komt er waarschijnlijk op neer nuttige functie reguliere expressies.

Voorbeeld 2

Oef... Eindelijk kunnen we terugkeren naar het voorbeeld met de IRC-chatbot. Laten we onze kennis in de praktijk brengen.

Als we de naam van de afzender van het bericht willen vastleggen wanneer hij 'Josh' schrijft, zou onze uitdrukking er ongeveer zo uitzien: /(\w+): .*Josh.*/ , en we kunnen het resultaat opslaan in een variabele in onze programmeertaal voor het antwoord.

Laten we eens kijken naar onze reguliere expressie. Hier volgen een of meer letters " : ", 0 of meer tekens, "Josh" en opnieuw 0 of meer tekens.

Opmerking: /.*word.*/ is een eenvoudige manier om een ​​string op te geven die “word” bevat, die wel of niet andere tekens kan bevatten.

In Python zou het er als volgt uitzien:
import re
patroon = re.compile(ur"(\w+): .*Josh.*") # Onze regex
string = u"Eli: Josh, ga je wasgoed verplaatsen" # Onze string
matches = re.match(pattern, string) # Test de string
who = matches.group(1) # Ontdek wie het bericht heeft gezegd
afdrukken(wie) # "Eli"
Merk op dat we gebruikten .groep(1) net als \1 . Dit is niets nieuws, behalve het gebruik van reguliere expressies in Python.

Het begin en het einde

Tot nu toe zijn we ervan uitgegaan dat de substrings die we zoeken zich overal in de string kunnen bevinden. Bijvoorbeeld, /(Jos)+h/ komt overeen met elke tekenreeks die op welke locatie dan ook "Jos-repeated-h" bevat.

Wat als we willen dat de string met dit patroon begint? Dit kan worden aangeduid als /^(Jos)+h/ , Waar ^ komt overeen met het begin van de regel. Insgelijks, $ markeert het einde van de regel.

Als we nu een string willen specificeren die alleen “Jos-repeating-h” bevat, zullen we schrijven /^(Jos)+h$/ .

Uitdrukkingen opsommen

Stel je voor dat je een reguliere expressie schrijft voor een sandwichrecept. Je weet niet of de klant de voorkeur geeft aan witbrood of zwartbrood, maar je moet er toch maar één kiezen. Hoe voeg ik selecteerbaarheid toe aan regex? Door te gebruiken overdrachten!

Hiermee kunt u sets met mogelijke waarden voor een groep tekens opgeven. Het ziet er zo uit: (wit|tarwe) . In de context van ons sandwichvoorbeeld wordt een van de opties geaccepteerd: 'wit' of 'tarwe'.

Om opsommingen aan te duiden, worden [vierkante haakjes] enigszins anders gebruikt. In plaats van de hele reeks is elk teken hier een variant. Dit kan handig zijn voor complexe reguliere expressies, omdat u één teken kunt vervangen door een complexere set.

Modificatoren

We hadden het over regex met /twee schuine strepen/, toch? We weten wat er tussen hen is, maar wat zou erbuiten moeten zijn?

Onverwachte wending: niets!

…links. Rechterkant, integendeel, kan heel veel nuttige dingen bevatten. Jammer dat we er zo lang niets over hebben gezegd!
Modificatoren definieer de regels waarmee reguliere expressies worden toegepast.

Hier is een lijst met de belangrijkste modifiers (van Regex101.com):

Wijziger Naam Beschrijving
G mondiaal Alle wedstrijden
M meerdere lijnen ^ en $ komen overeen met het begin en einde van elke regel
i ongevoelig Hoofdletterongevoelige vergelijking
X verlengd Spaties en tekst na # worden genegeerd
X extra \ met een willekeurige letter die geen speciale betekenis heeft, retourneert een fout
S enkele lijn Negeert karakters nieuwe lijn
u Unicode Sjabloonreeksen worden verwerkt als UTF-16
U onhebzuchtig Standaard gebruikt regex luie kwantificering. De U-modifier maakt kwantificering hebzuchtig
A verankerd Het patroon wordt gedwongen om ^
J duplicaat Maakt dubbele subpatroonnamen mogelijk

Voor de duidelijkheid: alle voorgaande voorbeelden waren hoofdlettergevoelig. Dit betekent dat als u zelfs maar één kleine letter vervangt door een hoofdletter, of omgekeerd, de tekenreeks niet langer overeenkomt met het patroon. Maar je kunt het hoofdletterongevoelig maken met behulp van een modifier i .

Stel dat Eli zo boos werd dat ze de chat begon te bombarderen met berichten met BRIEVEN van VERSCHILLENDE REGISTERS. Dit maakt ons niet bang, want ik ben er al! We kunnen de boze uitdrukking “Ik haat het leven met JOSH!!!” gemakkelijk definiëren /ik+te samenwonen met Josh!+/i . Onze regex is nu gemakkelijker te lezen en ook veel krachtiger en nuttiger. Verbazingwekkend!

Je kunt zelf met verschillende modifiers spelen. Naar mijn mening heb je er over het algemeen het meeste profijt van igm .

Wat is het volgende?

Ik hoop dat dit artikel mij in staat heeft gesteld om anders naar het werken met snaren te kijken en het redelijker te maken. We hebben nog maar de oppervlakte bereikt, maar je hebt al geleerd hoe je regex kunt gebruiken om een ​​aantal problemen op te lossen.

Er worden veel tekens en hun combinaties gebruikt in reguliere expressies. Meestal kom je ze tegen tijdens het verkennen van Stack Overflow, maar je kunt de betekenis van sommige uit eerdere voorbeelden raden (bijvoorbeeld \N - nieuw lijnsymbool). De basis is gelegd, maar er valt nog veel te leren.

Vinden volledige lijst combinaties van symbolen, en u kunt ook uw kennis testen.
Als dit voor jou een fluitje van een cent leek, probeer dan regex-kruiswoordpuzzels. Ze laten je echt zweten.

Na het punt

Dit artikel is een vertaling van de gids van Josh Hawkins. Josh is een gepassioneerde webontwikkelaar uit Alabama. Hij begon op negenjarige leeftijd met programmeren, waarbij hij zich concentreerde op videogames, desktop en sommige mobiele applicaties. Tijdens een stage in 2015 ontdekte Josh echter webontwikkeling en brak hij door in de wereld van open source gerelateerd aan dit vakgebied.

Voorheen gebruikte ik alleen (.*) onder reguliere expressies :) Verschillende vrienden adviseerden me sterk om dit probleem te onderzoeken. Maar omdat ik niet begreep waar ze gebruikt konden worden, stelde ik het uit tot betere tijden.

Alles veranderde toen ik nauwer moest samenwerken Google Analytics En Google-tag Manager bij Netpeak.

Zonder reguliere expressies te begrijpen, is het moeilijk voor te stellen hoe u filters, aangepaste segmenten in GA of regels in GTM correct kunt configureren.

Laten we eens kijken waar een beginner moet beginnen met het leren van reguliere expressies.

Wat zijn reguliere expressies

Reguliere expressies (RegExp) - sets tekens die worden gebruikt voor zoeken tekstreeksen, die aan de vereiste voorwaarden voldoet. Het resultaat van het toepassen van een reguliere expressie is een subset van gegevens die zijn geselecteerd op basis van de logica die in de expressie is ingebed. Reguliere expressies worden bij elke zoektaak gebruikt in een reeks gegevens waarvoor het volgens bepaalde regels nodig is om een ​​samenvatting te verkrijgen.

Syntaxis van reguliere expressies

De meeste tekens in reguliere expressies vertegenwoordigen zichzelf, met uitzondering van de groep speciale tekens "\/^$". | ? * + () ( )". Als deze tekens als teksttekens moeten worden weergegeven, moeten ze worden geëscaped met een backslash "\".

Als deze speciale tekens zonder backslash voorkomen, hebben ze een speciale betekenis in reguliere expressies:

  • “^” - dakje, circumflex of gewoon een vinkje. Begin van de lijn;
  • "$" is het dollarteken. Einde van de regel;
  • "." - periode. Elk karakter;
  • “*” - vermenigvuldigingsteken, asterisk. Een willekeurig aantal voorgaande karakters;
  • “+” is een pluspunt. 1 of meer eerdere karakters;
  • «?» - vraagteken. 0 of 1 eerdere tekens;
  • "()" - haakjes. Groepering van structuren;
  • «|» - verticale lijn. OF-operator;
  • "" - vierkante haken. Elk van de vermelde tekens, bereik. Als het eerste teken in deze constructie “^” is, werkt de array omgekeerd: het teken dat wordt gecontroleerd mag niet overeenkomen met wat tussen haakjes staat;
  • "( )" - accolades. Een symbool meerdere keren herhalen;
  • «\» - terugslag. Ontsnappende servicekarakters.

Er zijn ook speciale metatekens die enkele kant-en-klare structuren kunnen vervangen:

  • \b - geeft geen teken aan, maar de grens tussen tekens;
  • \d — digitaal karakter;
  • \D is een niet-cijferig teken;
  • \s — spatieteken;
  • \S is een teken zonder witruimte;
  • \w — alfanumeriek teken of onderstrepingsteken;
  • \W — elk ander teken dan alfabetisch of digitaal symbool of onderstrepen.

Vijf manieren om uw kennis van reguliere expressies te testen

Oefenen is erg belangrijk bij het leren van reguliere expressies. Hoe meer je oefent, hoe sneller je begint met het bouwen van de noodzakelijke structuren en het oplossen van de taken.

1. Reguliere expressies leren in een teksteditor

  • in de meeste gevallen hoeven speciale tekens niet te worden geëscaped;
  • Notepad++ behoudt constructies van eerdere zoekopdrachten;

2. Test uw kennis van reguliere expressies in Regex

Om alles te scannen URL-adressen alleen het eerste niveau van nesten, moet u de volgende instellingen in de service instellen:

Ik besloot een spiekbriefje te schrijven over reguliere expressies. Misschien zal ik ze ooit vergeten. Bovendien kan dit bericht worden beschouwd als een voortzetting van mijn serie Perl-tutorials.

1. Inleiding

Een paar woorden voor degenen die niet helemaal weten waar we het over hebben waar we het over hebben. Heb je ooit bestandsnaammaskers gezien - allerlei soorten *.html, bestandsnaam.(txt|csv), enz.? Reguliere expressies zijn dus dezelfde ‘maskers’, alleen complexer. In de juiste handen kunnen reguliere expressies een ongelooflijk krachtig hulpmiddel zijn. Op de een of andere manier worden ze in 95% van mijn scripts gebruikt.

Veel mensen zijn terecht van mening dat reguliere expressies méér zijn onafhankelijke taal programmeren dan onderdeel van welke taal dan ook. Reguliere expressies zijn beschikbaar in Perl, PHP, Python, JavaScript, configuratiebestanden Apache... Afhankelijk van de taal kunnen er kleine verschillen zijn in de syntaxis van reguliere expressies, maar de basisideeën zijn hetzelfde.

Daarom zal de verstrekte informatie, ondanks het feit dat alle voorbeelden in de notitie in Perl zijn geschreven, ook nuttig zijn voor programmeurs die een andere taal in hun werk gebruiken. Deze code in PHP bijvoorbeeld:

if (preg_match ("//" , $text ) ) (
// de tekst bevat cijfers
) anders (
// er staan ​​geen cijfers in de tekst
}

en deze in Perl:

als ($tekst =~ // ) (
# de tekst bevat cijfers
) anders (

}

doe hetzelfde. Zoals je misschien wel kunt raden uit de opmerkingen in de code, hier controle bezig of de string $text minstens één cijfer bevat.

2. Eenvoudige voorbeelden

Zoals altijd zullen we leren van voorbeelden. Vierkante beugels in reguliere expressies betekent "een van de vermelde tekens moet hier voorkomen." Bijvoorbeeld de bovenstaande uitdrukking komt overeen met elke tekenreeks die ten minste één cijfer bevat. Vergelijkbaar met de uitdrukking komt overeen met elke tekenreeks die ten minste één van de eerste drie letters bevat Latijns alfabet. Om welk personage dan ook te vertegenwoordigen, behalve opgegeven, wordt de invoer gebruikt [^abcdef], dat wil zeggen met deksel symbool onmiddellijk na de openingsvierkante haak.

Stel dat we moeten controleren of een string een teken uit het Latijnse alfabet bevat. Het is niet helemaal handig om alle 26 letters op te sommen, toch? Vooral voor dergelijke gevallen kunt u reguliere expressies gebruiken streepje tussen vierkante haken om een ​​geordende reeks tekens aan te duiden. Uitdrukking Elke tekenreeks die ten minste één kleine letter van het Latijnse alfabet bevat, komt overeen. Naar analogie kan het eerder gegeven voorbeeld met cijfers korter worden geschreven:

als ($tekst =~ // ) (
# de tekst bevat cijfers
) anders (
# er staan ​​geen cijfers in de tekst
}

En nog een paar voorbeelden:

als ($tekst =~ // ) (
# tekst bevat cijfers en/of kleine letters
# geschikt: abc, ZZaZZ, ===17
# niet geschikt: EPIC FAIL, @^*!@#
}

als ($tekst =~ /[^0-9]/ ) (
# de tekst bevat andere tekens dan cijfers
# past op: abc, 123abc456, 0x1111111111
# niet geschikt: 123, 123456, 9999999999
}

als ($tekst =~ // ) (
# de tekst bevat letters van het Latijnse alfabet
# geschikt: ___Abba___, zyx
# niet geschikt: 0123, ^_^
}

als ($tekst =~ // ) (
# tekst bevat cijfers en letters van A tot F
# geschikt: ***777***, DeadC0de, intel, 0_o
# niet geschikt: Xor, wiki
}

Laten we de taak ingewikkelder maken. Nu moeten we niet alleen de aan- of afwezigheid van bepaalde karakters controleren, maar ook of de string overeenkomt met een bepaald formaat. Hier zijn enkele eenvoudige voorbeelden:

if ($tekst =~ /num=/ ) (
# geschikt: num=1, some_num=000, bebenum=2(&^*
# niet geschikt: NUM=1, mijn_num=-1, num=abc
}

als ($tekst =~ / / ) {
# past:
#zzz zzz
#
# niet geschikt:
#
#
}

De oplettende lezer zal zich afvragen wat dit is plusteken staat het in de laatste reguliere expressie? Dit symbool betekent "een of meer tekens gespecificeerd vóór deze plus." Het symbool betekent vrijwel hetzelfde ster"van nul tot een willekeurig aantal tekens dat vóór het sterretje is opgegeven.” De uitdrukking bijvoorbeeld EEN+ komt overeen met een reeks van een of meer tekens A en de uitdrukking * - een willekeurig aantal cijfers, inclusief geen.

Soms moet het aantal tekens nauwkeuriger worden gespecificeerd. Dit kan gedaan worden met behulp van krullende beugels . De uitdrukking bijvoorbeeld {8} komt overeen met elke reeks van precies acht cijfers en de uitdrukking {3,8} — een reeks met 3 tot 8 tekens van het Latijnse alfabet.

Het nummer op de tweede positie mag niet worden gespecificeerd. Dat wil zeggen: de uitdrukking {3,} kan ook voorkomen. Het betekent ‘minstens drie kleine letters van het Latijnse alfabet’. Uitdrukking {0,} volledig vergelijkbaar met het sterretje, en {1,} - plus. Uitdrukking {0,1} kan korter worden geschreven met behulp van vraagteken.

Voorbeeld (niet het eenvoudigste, maar interessant):

als ($tekst =~ // ) {
# past:
#dfgd dfgdfg
#
# niet geschikt:
#
#
}

Als dit voorbeeld je hersenen doet koken, is het tijd om een ​​beetje te oefenen met reguliere expressies door testprogramma's te schrijven. Anders zal verder lezen je met een puinhoop in je hoofd achterlaten. Als alles tot nu toe duidelijk is, gaan we verder.

3. Hoe scheur je een stuk lijn uit?

Symbool verticale lijn(ook bekend als "pipe" of gewoon "stick") betekent in reguliere expressies "of". De uitdrukking bijvoorbeeld {20}|{25} komt overeen met alle tekenreeksen die 20 Latijnse tekens bevatten of 25 cijfers op een rij. Meestal wordt dit symbool gebruikt in combinatie met haakjes, ontworpen om delen van een reguliere expressie te groeperen. Voorbeeld:

if ($bestandsnaam =~ /back-up(19|20)(2)-(2)-(2)/) {
# geschikt: back-up2011-04-01, back-up1999-01-13
# niet geschikt: backup1873-12-12, backup2101-07-07
}

Haakjes hebben nog een andere functie. Met hun hulp kun je stukjes van de overeenkomstige lijnen afscheuren. IN PHP-resultaat wordt opgeslagen in de variabele die is opgegeven door het derde argument van de preg_match-functie. In Perl worden overeenkomsten voor het 1e, 2e...9e paar haakjes opgeslagen in de variabelen $1, $2,..., $9. Maar het is handiger om deze constructie te gebruiken:

als (mijn ($y, $m, $d) =
$bestandsnaam =~ /back-up((4))-((2))-((2))/) {
afdrukken;
}

De vraag is welk nummer moet worden gezocht naar een overeenkomst in de geretourneerde array als de reguliere expressie dit bevat genest haakjes? Het is eenvoudig: overeenkomsten worden in dezelfde volgorde geretourneerd als de openingshaakjes. Voorbeeld:

mijn $bestandsnaam = "./dumps/backup2011-04-01.tgz";
$bestandsnaam =~ /back-up((20|19)(2))-((2))-((2))/;
afdrukken "$1, $2, $3, $4 \N";
# levert op: 2011, 20, 04, 01

Soms willen we een deel van een uitdrukking groeperen, maar niet retourneren. Om dit te doen, moet je onmiddellijk na de openingsbeugel schrijven reeks van vraagteken en dubbele punt. Voorbeeld:

als (mijn ($y, $m, $d) =
$bestandsnaam =~ /back-up((?:20|19)(2))-((2))-((2))/) {
afdrukken "jaar = $y, maand = $m, dag = $d\n ";
}

Haakjes kunnen ook worden gevolgd door een vraagteken, plus of asterisk, wat aangeeft dat het construct tussen haakjes optioneel is, respectievelijk 1+ keer moet worden herhaald of 0+ keer moet worden herhaald. Het gebruik van accolades na haakjes is ook acceptabel.

4. Begin en einde van de regel

Vaak is het handig om in een reguliere expressie aan te geven waar een string moet beginnen en/of eindigen. De eerste wordt gedaan met behulp van dop-symbool aan het begin van de uitdrukking, de tweede - gebruikt dollarteken aan het einde. Voorbeelden:

als ($tekst =~ /^*/ ) (
# tekst die begint met een decimaal cijfer
# geschikt: 3, 801403, 6543bebebe
# niet geschikt: 0275, -123, abc11111
}

als ($tekst =~ /^0x(1,8)$/ ) (
# hexadecimaal getal in C-notatie
# geschikt: 0x5f3759df, 0xDEADBEEF
# niet geschikt: 0x1234xxx, xxx0x5678, xxx0x9ABCxxx
}

Niet moeilijk, toch? Houd er rekening mee dat bij het controleren van webformuliervelden argumenten moeten worden gebruikt voordat ze worden vervangen door een SQL-query, enz. Noodzakelijkerwijs moet worden gecontroleerd alle string, zoals gedaan in de laatste reguliere expressie.

Opmerking: Als iemand geïnteresseerd is in wat deze "magische getallen" 0x5f3759df en 0xDEADBEEF zijn, raadpleeg dan Wikipedia.

5. Speciale tekens

Naast de hierboven genoemde speciale tekens moet er ook speciale aandacht aan worden besteed punt. Ze bedoelt elk ander teken dan de nieuwe regel. Gebruiksvoorbeeld:

if (mijn ($naam ) = $arg =~ /^--naam=(.+)$/ ) (
afdrukken "Hallo, $naam! \N";
}

Standaard produceren reguliere expressies wat wordt genoemd hebzuchtig parseren. Met andere woorden: er wordt gezocht naar matches maximale lengte. Als we een punt gebruiken, kan dit problemen veroorzaken. We moeten bijvoorbeeld wat tekst uit honderden HTML-pagina's verwijderen met ongeveer de volgende inhoud:

<span > Tekst<em > tekst</em> tekst</span> Bron: http://site/</span>

De volgende code retourneert niet wat we zouden willen:

# de reguliere expressie bevat een schuine streep, dus
# moet in plaats daarvan een ander scheidingsteken gebruiken
(.*)#;
print $tekst;
# drukt de langste overeenkomst af:
#Tekst tekst tekstbron: http://site/

Dit is wat er gebeurt als je hebzuchtig parseren uitschakelt (let op het vraagteken):

mijn ($tekst) = $data =~ m # (.*?)#;
print $tekst;
# zal de eerste overeenkomst afdrukken:
#Tekst tekst tekst

Ja, volgende regels doe hetzelfde:

# reguliere toegang...
$tekst =~ /({4})-({2})-({2})/ ;
# is eigenlijk slechts een afkorting voor de operator m//
$tekst =~ m/((4))-((2))-((2))/;
# in plaats van een schuine streep kun je andere haakjes gebruiken:
$tekst =~ m ( ([ 0 - 9 ] ( 4 ) ) - ( [ 0 - 9 ] ( 2 ) ) - ( [ 0 - 9 ] ( 2 ) ) );
$tekst =~ m< ([ 0 - 9 ] { 4 } ) - ([ 0 - 9 ] { 2 } ) - ([ 0 - 9 ] { 2 } ) >;
$tekst =~ m [ ([ 0 - 9 ] ( 4 ) ) - ( [ 0 - 9 ] ( 2 ) ) - ( [ 0 - 9 ] ( 2 ) ) ] ;
$tekst =~ m (([ 0 - 9 ] ( 4 ) ) - ( [ 0 - 9 ] ( 2 ) ) - ( [ 0 - 9 ] ( 2 ) ) );
# of zelfs symbolen zoals deze:
$tekst =~ m ! ([ 0 - 9 ] ( 4 ) ) - ( [ 0 - 9 ] ( 2 ) ) - ( [ 0 - 9 ] ( 2 ) ) !;
$tekst =~ m | ([ 0 - 9 ] ( 4 ) ) - ( [ 0 - 9 ] ( 2 ) ) - ( [ 0 - 9 ] ( 2 ) ) |;
$tekst =~ m #({4})-({2})-({2})#;
# evenals hoofdletters, aanhalingstekens, dubbele punt, komma, punt, ...

Waarom waren er zoveel manieren nodig om reguliere expressies te schrijven? Stel je voor dat de uitdrukking schuine strepen, punten, komma's en andere symbolen bevat, maar geen uitroepteken. Dan kunnen we uiteraard geen schuine strepen, punten, enzovoort gebruiken om het begin en einde van een reguliere expressie aan te geven, maar uitroepteken- Kan.

Vaak moet je in reguliere expressies gebruiken terugslag. Geplaatst vóór een punt, haakjes, plus, hoofdletter en andere symbolen, betekent dit "het volgende symbool betekent precies het symbool, en niet iets anders." U kunt als volgt bijvoorbeeld een bestandsextensie bepalen aan de hand van de naam:

# backslash ontsnapte punt
# betekent een punt, niet "een teken"
mijn ($ext ) = $fnaam =~ /\.(+)$/ ;
afdrukken "bestandsnaam: $fname, extensie: $ext\n ";

Bovendien wordt backslash gebruikt in de volgende notatie:

  • \T— geeft een tabteken aan ( T ab)
  • \R En \N- regelteruglooptekens ( R eturn) en nieuwe regel ( N nieuwe lijn)
  • \xNN— komt bijvoorbeeld overeen met een teken met ASCII-code NN \x41 komt overeen hoofdletter A van het Latijnse alfabet
  • \S- komt overeen met een spatie ( S tempo), tab, nieuwe regel of regelterugloop
  • \D- betekent elk getal ( D igit), of beter gezegd, wat in Unicode als een getal wordt beschouwd (zie dianummer 102 in deze presentatie)
  • \w- betekent het zogenaamde “woord” ( w ord), analoog

In de laatste drie uitdrukkingen schrijft u de letter in hoofdletter betekent ontkenning. Bijvoorbeeld, \D komt overeen met de uitdrukking [^0-9] , \W- uitdrukking [^0-9a-zA-Z_], A \S- elk teken dat geen witruimte bevat.

Al deze "letter"-uitdrukkingen kunnen tussen vierkante haken worden gebruikt. De uitdrukking bijvoorbeeld volledig gelijkwaardig .

De uitingen verdienen bijzondere aandacht \B En \B, wat de grens van een woord betekent (in dezelfde betekenis van "woord" als in het geval van \w) en de afwezigheid van respectievelijk een woordgrens. De uitdrukking bijvoorbeeld perl\b komt overeen met de tekenreeks "perl rulez!", maar komt niet overeen met "perlmonk". Met expressie perl\B alles is precies het tegenovergestelde. Ik hoop dat het idee duidelijk is.

En nog een voorbeeld:

#brekend volledige naam bestand naar pad en naam
mijn ($pad , $fname ) = $full_name =~ /^(.*)\/([^\/]+)$/ ;

Het illustreert het gebruik van de backslash om aan een teken te ontsnappen dat wordt gebruikt om de grenzen van reguliere expressies aan te geven. IN in dit voorbeeld dit is een voorwaartse schuine streep.

6. Modificatoren

Het gedrag van reguliere expressies kan worden gewijzigd met behulp van modifiers. Zoals je misschien al hebt gemerkt, wordt de overeenkomst van een string met een reguliere expressie bijvoorbeeld hoofdlettergevoelig gecontroleerd. U kunt dit gedrag wijzigen met de #-modifier (.*?)#G;
# wees voorzichtig bij het gebruik van /g in scalaire context
# details hier: http://koorchik.blogspot.com/2011/07/perl-5.html
druk "$_ af \N" voor (@woorden);

Zoals hierboven vermeld, geeft een punt elk teken aan behalve het newline-teken. U kunt dit gedrag wijzigen met behulp van een modifier /S:

# haal de inhoud van het artikel uit het HTML-bestand,
# die meer dan één of twee regels kan bevatten
mijn ($artikel) = $html =~ m #

(.*?)
#S;

Trouwens, als je in een reguliere expressie “elk teken” moet aangeven zonder een modifier te gebruiken /S, gebruik de uitdrukking [\d\D]. Het betekent “elk teken dat een cijfer is of geen cijfer is”, dat wil zeggen, welk teken dan ook.

Ten slotte houdt niets u tegen om meerdere modifiers tegelijkertijd te gebruiken:

# verwijder alles wat vetgedrukt is uit het HTML-bestand
mijn @woorden = $html =~ m # (.*?)#gi;
# zal werken voor , of zelfs

Toevoeging: Een andere nuttige modifier is /O. Het betekent 'de reguliere expressie slechts één keer compileren'. IN sommige In sommige gevallen kan deze modifier het script aanzienlijk versnellen. Ik ben er echter niet zeker van dat het ergens anders wordt ondersteund, behalve in Perl. Bedankt voor de tip kameraad

Hier zijn enkele voorbeelden van reguliere expressies.

    karova - duidelijk een sjabloon waarin het woord karova past;

    \b(shift|unshift|pop|push|splice)\b - een van de genoemde woorden;

    ^\s+ - een of meer spaties of tabs aan het begin van een regel.

In reguliere expressies vertegenwoordigen alfanumerieke tekens meestal zichzelf. Het Hello-patroon geeft bijvoorbeeld aan dat er moet worden gezocht naar het teken H, gevolgd door e, vervolgens l, enz.

Als een symbool moeilijk of onhandig is om letterlijk op te geven, kunt u letterlijke waarden gebruiken die al bij ons bekend zijn: \n , \t en andere. Dit betekent dat het \-teken in de reguliere expressie zichzelf niet langer kan aanduiden, omdat het de betekenis verandert van het teken dat erop volgt: in het bijzonder geeft de letter n, samen met het voorgaande backslash-teken, het teken aan het einde van de regel aan. Als u het teken \ zelf in het patroon wilt opnemen, moet u de letterlijke \\ gebruiken.

Er zijn andere symbolen die een speciale betekenis krijgen in patronen in plaats van zichzelf te vertegenwoordigen. Dergelijke symbolen worden genoemd metatekens. Laten we een paar voorbeelden geven van metatekens, zonder hun speciale betekenis nog aan te geven (de lijst is niet uitputtend): \.-()()?*+^$| .

Sommige karakters blijken niet altijd metakarakters te zijn, maar pas als ze in een bepaalde context vallen. Sommige metatekens hebben verschillende betekenissen, afhankelijk van de context.

Als u een metateken in een reguliere expressie moet invoegen, waardoor deze niet langer betekenisvol is, moet u deze beschermen ( schild), waarbij een backslash voor hem wordt geplaatst. Een plusteken in een reguliere expressie wordt bijvoorbeeld ingevoegd als \+ .

Het patroon duidt een van de tekens aan die tussen vierkante haken staan. Als we bijvoorbeeld geïnteresseerd zijn in het woord Hallo, maakt het niet uit of het met een hoofdletter of klein is, het patroon ziet er als volgt uit: ello. Hier is een patroon dat een kleine klinkerletter in het Engelse alfabet voorstelt: . Een ander voorbeeld is een tekenklasse die uit beide vierkante haken bestaat: [\[\]] .

Als de tekenklasse opeenvolgende tekens in de codetabel bevat, is het voldoende om de eerste en op te geven laatste karakters, met een koppelteken ertussen. Bijvoorbeeld een klasse die een aanduidt decimaal cijfer, kan worden ingesteld als . Een letter van het Engelse alfabet wordt aangeduid als (hier vertrouwen we op het feit dat in elke codetabel hoofdletters en kleine letters Engelse brieven ga in doorlopende blokken naar binnen alfabetische volgorde; een blok kleine letters volgt echter niet onmiddellijk op een blok hoofdletters).

Het is mogelijk om een ​​karakterklasse te definiëren die bestaat uit alle karakters behalve de genoemde karakters - de zogenaamde karakterklasse ontkenning. Om dit te doen, wordt onmiddellijk na het openingsvierkante haakje vóór de opsomming een circumflex-teken ^ ingevoegd. Elk teken dat geen getal is, kan worden weergegeven als [^0-9] .

Er zijn speciale notaties voor enkele populaire karakterklassen:

Wanneer een tekenreeks met succes wordt vergeleken met een reguliere expressie, wordt elk teken of elke tekenklasse in het patroon gekoppeld aan een teken in de tekenreeks. Maar er zijn constructies die niet de aanwezigheid van een bepaald personage aangeven, maar een bepaalde (lege) plek in de rij. Dergelijke constructies worden genoemd bindingen, of ankers

De meest gebruikte ankers zijn het anker (^) en het einde ($) van de string. Het anker aan het begin van de lijn moet aan het begin van het patroon worden geplaatst, en het anker aan het einde van de lijn moet aan het einde worden geplaatst.

Russische woorden als tegengif, antisemitisme of antideeltje passen bijvoorbeeld in het patroon ^anti. Zonder een link zouden regels die niet beginnen met “anti-”, maar deze lettercombinatie erin bevatten, ook geschikt zijn voor bijvoorbeeld mercantilisme. Om te zoeken naar woorden die eindigen op “-tsya” heb je het patroon tsya$ nodig (we zijn er bijna 100% zeker van dat al dergelijke woorden wederkerende werkwoorden in de infinitief zijn). Niets houdt u tegen om beide bindingen in uw sjabloon te gebruiken.

Een ander nuttig anker is het woord grensanker \b . Het komt overeen met de spatie in een string tussen tekens, waarvan er één van klasse \w is en de andere van klasse \W (in willekeurige volgorde). Dit anker kan ook overeenkomen met het begin of einde van een string (in dat geval wordt aangenomen dat de string omgeven is door denkbeeldige tekens uit de klasse \W).

Als we op zoek zijn naar een fragment dat in een van de verschillende sjablonen zou moeten passen, moeten we deze sjablonen opsommen, gescheiden door een pipe | . Bijvoorbeeld maandag|dinsdag|woensdag|donderdag|vrijdag|zaterdag|zondag. Om van de lijst met alternatieven een onafhankelijke eenheid te maken en gescheiden van de aangrenzende, moet deze tussen haakjes worden geplaatst. Het patroon Respected betekent bijvoorbeeld de string Respected gevolgd door een van de strings th of th. Zonder de haakjes zou het patroon Dear|aya een van de strings Dear of aya aangeven. Beugels hebben een belangrijk neveneffect, dat zal worden besproken in het gedeelte 'Groeperen en vastleggen'.

Om aan te geven hoe vaak een patroon herhaald kan worden, de zogenaamde kwantoren(van het Latijnse woord quantum- Hoeveel):

Kwantificatoren * , + en ? zijn overbodig omdat ze anders kunnen worden uitgedrukt met behulp van accolades. Namelijk, * is gelijk aan (0,) , + is gelijk aan (1,) , hè? - hetzelfde als (0,1) . Maar deze kwantoren worden heel vaak gebruikt en verdienen daarom een ​​aparte benaming.

Als het patroon waarop de kwantificator wordt toegepast complexer is dan slechts één teken of klasse van tekens, moet het tussen haakjes worden geplaatst.

Hier zijn enkele voorbeelden:

    ^\d+$ - een reeks van een of meer decimale cijfers (een patroon voor niet-negatieve gehele getallen in decimale notatie);

    ^\-?\d+$ - hetzelfde, maar voor alle (mogelijk negatieve) gehele getallen;

    ^\-?(\d+(\.\d*)?|\.\d+)$ - patroon voor reële getallen;

Laten we het laatste voorbeeld in meer detail bekijken. Naast het optionele minteken aan het begin bevat het patroon een groep met twee alternatieven: \d+(\.\d*)? en \.\d+ . Bevat het eerste alternatief een verplicht geheel getal \d+ (minstens één cijfer), gevolgd door een optioneel deel (\.\d*)? . In het fractionele deel, als die er is, is die er decimaalteken, en misschien een paar cijfers. Dit alternatief komt dus overeen met regels 15, 15., 15.487. Er is een ander alternatief nodig voor strings zoals .618 die ontbreken hele deel- in veel computertalen dit bericht heeft bestaansrecht.

Als de eenvoudigste elementen van een reguliere expressie (tekens, tekenklassen en ankers) in een rij worden geschreven, betekent dit dat wanneer een patroon in een string wordt doorzocht, deze elementen opeenvolgend in dezelfde volgorde worden vergeleken met delen van de string. . Dit bevel wordt geschonden als er alternatieven worden toegepast. Je kunt je voorstellen dat een samengestelde reguliere expressie bestaat uit eenvoudige expressies met behulp van twee bewerkingen: sequentieel samenvoegen ( composities) en alternatieven. Compositie is een analoog van de vermenigvuldigingsbewerking in de rekenkunde. Een alternatief is een analoog van optelling. De eerste overeenkomst met rekenkunde is dat de alternatieve bewerking een lagere prioriteit heeft dan compositie, waardoor het groeperen van haakjes nodig kan zijn, zoals in het Dear-voorbeeld.

Opmerking

Veel, maar niet alle, rekenwetten zijn ook van toepassing op reguliere expressies:

commutativiteit van het alternatief x | y = y | X ; associativiteit van alternatief x | j | z = x |

j | z; compositie associativiteit

x ⁣ y ⁣ z = X ⁣ y ⁣ z ;

distributiviteit van het alternatief ten opzichte van de compositie (links en rechts)

x ⁣ y |

Hier komt de grip goed van pas. We sluiten het deel van de sjabloon in dat volgens ons plan zou moeten overeenkomen met de naam tussen haakjes: (\S+[int]th) acid. Vervolgens zal de machine, nadat hij een vermelding van acid in de tekst heeft gevonden, zijn naam (wat overeenkomt met het sjabloonfragment tussen haakjes) opslaan in een speciale variabele - opvangbuffer

Een reguliere expressie kan meerdere capture-groepen bevatten. Dergelijke groepen kunnen elkaar niet alleen volgen, maar ook in elkaar nestelen. Met andere woorden: de reguliere expressie moet op dezelfde manier worden afgewogen tegen haakjes als besproken in hoofdstuk 23.' Controle van het evenwicht van de beugels" (Dit geldt uiteraard alleen voor haakjes die dienen voor het groeperen en vastleggen; haakjes voorafgegaan door een backslash hebben geen effect op het groepsevenwicht). Als de zoekopdracht succesvol is, zal elke groep een deel van de tekst vastleggen: het eerste - in de eerste buffer, het tweede - in de tweede, enzovoort. Hoe worden groepen genummerd als ze in elkaar zijn genest? De nummering is in de volgorde waarin de openingshaakjes verschijnen:

2 4 5 ┝┑ ┝┑┝┑ (()(()())) │ ┝━━━━┙│ │ 3 │ ┝━━━━━━━━┙ 1

Indien gewenst kan een groep worden uitgesloten van de nummering, dat wil zeggen worden beroofd van zijn "agressieve" functie, waardoor alleen de groeperingsfunctie overblijft. Om dit te doen, gebruiken we in plaats van groepsscheidingstekens (⋯) ( ?: ⋯). Hier staat een vraagteken Niet geeft een kwantor aan omdat de kwantor moet worden voorafgegaan door een teken, een tekenklasse of een groep.

Het gebruik van genummerde capture-groepen is niet altijd handig, vooral niet bij grote reguliere expressies. Plaats het gewoon in de sjabloon nieuwe groep vastleggen, omdat de nummering verloren gaat. Dan zul je op alle plaatsen in het programma waar opnamebuffers op nummer worden benaderd correcties moeten aanbrengen. U kunt echter een naam aan een groep koppelen, waardoor u met die naam toegang krijgt tot de corresponderende buffer. Om een ​​benoemde groep te maken, gebruikt u scheidingstekens ( ? ⋯) , waarbij de gewenste naam wordt vervangen door naam.

Delen van een string die in buffers zijn vastgelegd, kunnen op twee manieren worden gebruikt. Ten eerste kan een programma dat een reguliere expressie gebruikt om te zoeken of te vervangen, naar buffers verwijzen als speciale variabelen. Dit gebruik wordt besproken in de sectie “Operators zoeken en vervangen”. De tweede mogelijkheid betreft het gebruik van links naar groepen rechtstreeks in een reguliere expressie, zie de paragraaf “Backlinks”.

Beschouw het probleem van het vinden van woorden die drie identieke klinkerletters op een rij bevatten. De naïeve oplossing [aеооуеуя](3) waarbij gebruik wordt gemaakt van kwantoren zal niet werken, aangezien dit patroon strings met drie opeenvolgende klinkers matcht, maar niet noodzakelijkerwijs dezelfde. We verwerpen verontwaardigd een monsterlijke oplossing met een volledige lijst van alternatieven, aaa|eeee|yoyo|iii|oooo|uuu|eeee|yuyuu|yayay: het is tenslotte de moeite waard om een ​​andere, uitgebreidere symbolische klasse te nemen, of de drie in de te vervangen kwantificator met een grotere waarde, zoals de sjabloongrootte, zal catastrofaal toenemen.

Nog steeds mogelijk elegante oplossing, met behulp van opnamegroepen. Laten we de klinker in een groep vastleggen en vervolgens verwijzen naar de inhoud van de opnamebuffer. Verwijzingen naar de eerste, tweede en derde buffers worden in reguliere expressie geschreven als \g1 , \g2 , \g3 . De oplossing is dus het patroon ([aeeioueyuya])\g1(2) . Houd er rekening mee dat de verwijzing naar de capture-buffer strikt na de corresponderende groep in de reguliere expressie moet komen.

Backlinks kan niet alleen verwijzen naar genummerde buffers, maar ook naar benoemde buffers. Dergelijke koppelingen zien eruit als \k , waarbij, nogmaals, in plaats van de naam een ​​specifieke naam staat. Ons voorbeeld kan worden herschreven met behulp van benoemde groepen: (? [aeeyoooeyya])\k {2} (medeklinker- medeklinker).

Soms is er behoefte aan een zoekopdracht die geen onderscheid maakt tussen kleine letters en in hoofdletters. Deze zoekopdracht wordt genoemd hoofdletterongevoelig (hoofdletterongevoelig). In plaats van letters overal in het patroon te vervangen door klassen van twee letters (a → , b → , ...), omsluiten we het patroon eenvoudigweg in speciale groep, waardoor de hoofdletterongevoelige zoekmodus wordt ingeschakeld: (? i:⋯). Zo'n groep is geen capture-groep. Als de hoofdletterongevoelige zoekactie alleen op een deel van de reguliere expressie moet worden geïmplementeerd, moet alleen het vereiste deel in de groep worden geplaatst.

Integendeel, als een deel van de reguliere expressie waarin de hoofdlettergevoelige zoekopdracht wordt uitgevoerd deze modus moet uitschakelen, dan kunt u terugkeren naar de reguliere, hoofdlettergevoelige zoekopdracht met behulp van de groep ( ?-i: ⋯) .

Hoofdlettergevoelige/ongevoelige modi hebben alleen invloed op letters. Wat telt als een letter en wat niet, hangt af van de taal, evenals de regels voor het matchen tussen hoofdletters en kleine letters. Vanuit het oogpunt van de Engelse taal is het symbool Ш bijvoorbeeld geen letter. In de Duitse taal is er de letter ß (de hoofdversie van deze letter bestaat trouwens uit twee letters SS: Carl Friedrich Gauß. → CARL FRIEDRICH GAUSS).

Het spiekbriefje is een algemene gids voor reguliere expressiepatronen zonder rekening te houden met de specifieke kenmerken van welke taal dan ook. Het wordt gepresenteerd in de vorm van een tabel die op één bedrukt vel A4-formaat past. Gemaakt onder een Creative Commons-licentie, gebaseerd op een spiekbriefje geschreven door Dave Child ().

Houd er rekening mee dat verschillende programmeertalen reguliere expressies ondersteunen in verschillende mate, waardoor u mogelijk een situatie tegenkomt waarin sommige van de genoemde functies niet werken. Voor degenen die net kennis maken met reguliere expressies, wordt deze vertaling van de opmerkingen van de auteur op het spiekbriefje aangeboden. Het laat je kennismaken met enkele van de technieken die worden gebruikt bij het bouwen van reguliere expressiepatronen.

Ankers in reguliere expressies geven het begin of einde van iets aan. Bijvoorbeeld lijnen of woorden. Ze worden weergegeven door bepaalde symbolen. Een patroon dat overeenkomt met een tekenreeks die begint met een getal, ziet er bijvoorbeeld als volgt uit:

Hier geeft het teken ^ het begin van de regel aan. Zonder dit zou het patroon overeenkomen met elke string die een cijfer bevat.

Tekenklassen in reguliere expressies komen in één keer overeen met een bepaalde reeks tekens. \d komt bijvoorbeeld overeen met elk getal van 0 tot en met 9, \w komt overeen met letters en cijfers, en \W komt overeen met alle tekens behalve letters en cijfers. Het patroon dat letters, cijfers en spaties identificeert, ziet er als volgt uit:

POSIX

POSIX is een relatief nieuwe toevoeging aan de reguliere expressiefamilie. Het idee is, net als bij tekenklassen, om snelkoppelingen te gebruiken die een bepaalde groep tekens vertegenwoordigen.

Bijna iedereen heeft in het begin moeite met het begrijpen van affirmaties, maar naarmate je er meer vertrouwd mee raakt, zul je merken dat je ze vrij vaak gebruikt. Beweringen bieden een manier om te zeggen: 'Ik wil elk woord in dit document vinden dat de letter 'q' bevat en niet wordt gevolgd door 'werty'.

[^\s]*q(?!werty)[^\s]*

De bovenstaande code begint met het zoeken naar andere tekens dan spatie ([^\s]*), gevolgd door q . De parser komt dan tot een toekomstgerichte bewering. Hierdoor wordt het voorgaande element (teken, groep of tekenklasse) automatisch voorwaardelijk gemaakt: het komt alleen overeen met het patroon als de bewering waar is. In ons geval is de verklaring negatief (?!), dat wil zeggen dat hij waar zal zijn als wat erin wordt gezocht, niet wordt gevonden.

De parser controleert dus de volgende paar tekens aan de hand van het voorgestelde patroon (werty). Als ze worden gevonden, is de bewering onwaar, wat betekent dat het teken q wordt “genegeerd”, dat wil zeggen dat het niet overeenkomt met het patroon. Als werty niet wordt gevonden, is de bewering waar en is alles in orde met q. Vervolgens gaat het zoeken verder naar alle andere tekens dan spatie ([^\s]*).

Deze groep bevat voorbeeldsjablonen. Met hun hulp kun je zien hoe reguliere expressies in de dagelijkse praktijk kunnen worden gebruikt. Houd er echter rekening mee dat ze niet noodzakelijkerwijs in elke programmeertaal zullen werken, aangezien elk van hen dat wel doet individuele kenmerken en verschillende niveaus van ondersteuning voor reguliere expressies.

Met kwantoren kunt u een deel van een patroon definiëren dat meerdere keren achter elkaar moet worden herhaald. Als u bijvoorbeeld wilt weten of een document een reeks van 10 tot 20 (inclusief) letters "a" bevat, kunt u dit patroon gebruiken:

EEN(10,20)

Kwantificeerders zijn standaard ‘hebzuchtig’. Daarom komt de kwantor +, wat 'een of meerdere keren' betekent, overeen met de maximaal mogelijke waarde. Soms veroorzaakt dit problemen, in welk geval je de kwantor kunt vertellen niet langer hebzuchtig te zijn ('lui' te worden) door een speciale modificator te gebruiken. Kijk naar deze code:

".*"

Dit patroon komt overeen met tekst tussen dubbele aanhalingstekens. Uw bronregel kan er echter ongeveer zo uitzien:

Hallo wereld

De bovenstaande sjabloon vindt de volgende subtekenreeks in deze regel:

"helloworld.htm" title="Hallo wereld" !}

Hij bleek te hebzuchtig en pakte het grootste stuk tekst dat hij kon.

".*?"

Dit patroon komt ook overeen met alle tekens tussen dubbele aanhalingstekens. Maar de luie versie (let op de modifier?) zoekt naar de kleinst mogelijke gebeurtenis en zal daarom elke substring vinden dubbele aanhalingstekens afzonderlijk:

"Hallowereld.htm" "Hallo wereld"

Reguliere expressies gebruiken bepaalde tekens om verschillende delen van een patroon weer te geven. Er doet zich echter een probleem voor als u een van deze tekens in een string moet vinden, net als een gewoon teken. Een punt in een reguliere expressie betekent bijvoorbeeld ‘elk teken, behalve een regeleinde’. Als je een punt in een string wilt vinden, kun je niet zomaar " gebruiken. » als sjabloon - dit zal ertoe leiden dat u bijna alles kunt vinden. U moet de parser dus vertellen dat deze punt als een gewone punt moet worden beschouwd en niet als "een teken". Dit gebeurt met behulp van een ontsnappingsbord.

Een escape-teken dat voorafgaat aan een teken, zoals een punt, zorgt ervoor dat de parser de functie ervan negeert en het als een normaal teken behandelt. Er zijn verschillende karakters die in de meeste sjablonen en talen een dergelijke ontsnapping vereisen. Je kunt ze vinden in de rechter benedenhoek van het spiekbriefje (“Metasymbolen”).

Het patroon voor het vinden van een punt is:

\.

Ander speciale karakters in reguliere expressies komen ongebruikelijke elementen in de tekst overeen. Regeleinden en tabs kunnen bijvoorbeeld op het toetsenbord worden getypt, maar veroorzaken waarschijnlijk verwarring bij programmeertalen. Het escape-teken wordt hier gebruikt om de parser te vertellen het volgende teken als speciaal te behandelen in plaats van een gewone brief of nummer.

Stringvervanging wordt in detail beschreven in de volgende paragraaf, “Groepen en bereiken”, maar het bestaan ​​van “passieve” groepen moet hier worden vermeld. Dit zijn groepen die tijdens de vervanging worden genegeerd, wat erg handig is als u een 'of'-voorwaarde in een patroon wilt gebruiken, maar niet wilt dat die groep deelneemt aan de vervanging.

Groepen en bereiken zijn heel erg handig. Het is waarschijnlijk gemakkelijker om met bereiken te beginnen. Hiermee kunt u een reeks geschikte tekens opgeven. Als u bijvoorbeeld wilt controleren of een string hexadecimale cijfers bevat (0 t/m 9 en A t/m F), gebruikt u het volgende bereik:

Om het tegenovergestelde te controleren, gebruikt u een negatief bereik, dat in ons geval op elk teken past, behalve cijfers van 0 tot 9 en letters van A tot F:

[^A-Fa-f0-9]

Groepen worden het vaakst gebruikt als er een 'of'-voorwaarde nodig is in een patroon; wanneer u vanuit een ander deel naar een deel van een sjabloon moet verwijzen; en ook bij het vervangen van snaren.

Het gebruik van "or" is heel eenvoudig: het volgende patroon zoekt naar "ab" of "bc":

Als het in een reguliere expressie nodig is om naar een van de voorgaande groepen te verwijzen, moet je \n gebruiken, waarbij je in plaats van n een getal vervangt de gewenste groep. Misschien wilt u een patroon dat overeenkomt met de letters "aaa" of "bbb", gevolgd door een cijfer en vervolgens dezelfde drie letters. Dit patroon wordt geïmplementeerd met behulp van groepen:

(aaa|bbb)+\1

Het eerste deel van het patroon zoekt naar "aaa" of "bbb", waarbij de gevonden letters in een groep worden gecombineerd. Dit wordt gevolgd door een zoektocht naar een of meer cijfers (+), en tenslotte \1. Het laatste deel van het patroon verwijst naar de eerste groep en zoekt naar hetzelfde. Er wordt gezocht naar een overeenkomst met de tekst die al in het eerste deel van het patroon is gevonden, en niet naar een overeenkomst daarmee. Dus "aaa123bbb" voldoet niet aan het bovenstaande patroon, omdat \1 achter het nummer naar "aaa" zal zoeken.

Een van de meest handige hulpmiddelen in reguliere expressies is tekenreeksvervanging. Wanneer u tekst vervangt, kunt u naar de gevonden groep verwijzen met $n . Stel dat u alle woorden 'wens' in de tekst vetgedrukt wilt markeren. Om dit te doen, moet u een vervangingsfunctie voor reguliere expressies gebruiken, die er als volgt uit kan zien:

Vervangen(patroon, vervanging, onderwerp)

De eerste parameter ziet er ongeveer zo uit (je hebt mogelijk een paar extra tekens nodig voor deze specifieke functie):

([^A-Za-z0-9])(wens)([^A-Za-z0-9])

Het zal alle voorkomens van het woord "wens" vinden, samen met de vorige en volgende tekens, zolang het maar geen letters of cijfers zijn. Dan zou je vervanging er als volgt uit kunnen zien:

$1$2$3

Het zal de volledige string vervangen die met behulp van het patroon is gevonden. We beginnen te vervangen door het eerste gevonden teken (dat geen letter of cijfer is), en markeren het $1 . Zonder dit zouden we dit teken eenvoudigweg uit de tekst verwijderen. Hetzelfde geldt voor het einde van de vervanging ($3). In het midden hebben we toegevoegd HTML-tag voor vetgedrukt (je kunt natuurlijk CSS of ), waardoor ze de tweede groep worden toegewezen die is gevonden met behulp van de sjabloon ($ 2).

Sjabloonmodifiers worden in verschillende talen gebruikt, met name in Perl. Hiermee kunt u de manier wijzigen waarop de parser werkt. De i-modifier zorgt er bijvoorbeeld voor dat de parser gevallen negeert.

Reguliere expressies in Perl worden aan het begin en aan het einde omgeven door hetzelfde teken. Dit kan elk teken zijn (meestal wordt “/” gebruikt) en het ziet er als volgt uit:

/patroon/

Modifiers worden als volgt aan het einde van deze regel toegevoegd:

/patroon/ik

Ten slotte bevat het laatste deel van de tabel metatekens. Dit zijn tekens die een speciale betekenis hebben in reguliere expressies. Dus als je een van deze als een gewoon personage wilt gebruiken, moet deze worden geëscaped. Gebruik het volgende patroon om te controleren of er haakjes in de tekst voorkomen:

Echt bedankt. vooral voor de verduidelijking. Graag gedaan :) Hartelijk dank. Het zal nodig zijn om alles volledig te verwijderen. !? 2 lails: Reguliere expressies zijn hier niet nodig. Substr() en strpos() zullen je helpen als we het hebben over PHP, of hun analogen in andere talen. Het was interessant om over de uitspraken te lezen, ik begin het langzamerhand te begrijpen. Op deze manier zal het duidelijker zijn: http://pcreonline.com/OazZNu/ Hallo. Kunt u mij vertellen waarom “achterwaarts gerichte uitspraken” bij mij niet werken in FireFox? Mozilla's RegExp-hulp heeft ze helemaal niet. Is het echt onmogelijk in Fox? =((( Goedemorgen, achterwaarts gerichte uitspraken worden niet ondersteund door JavaScript, dus naar alle waarschijnlijkheid zullen ze ook niet werken in andere browsers. Er staat meer op deze link gedetailleerde informatie over de beperkingen van reguliere expressies in JavaScript.
Goed gedaan! geef mij een high five!
Bedankt! Kort en duidelijk! Hm. Dank u) Dank u! bedankt, het heeft enorm geholpen, heel erg bedankt!

Bedankt voor het artikel! Vertel me eens, wat als u de wachtwoordinvoer moet beperken tot cijfers en niet meer dan vijf letters?
Hallo, het spiekbriefje is goed voor iedereen, maar het zou mogelijk zijn om de zebra lichter te maken, want als je zwarte letters afdrukt
donkere achtergrond

niet erg bedankt. Een kleine vraag: u moet de waarden tussen start= en & vinden, maar tegelijkertijd deze bereikgrenzen uitsluiten van de uitvoer. Hoe u het voltooide bereik kunt vinden: start=.(1,)&

Maar er is nog steeds niet genoeg kennis over hoe grenzen kunnen worden opgeheven. Ik zou dankbaar zijn voor uw hulp.
Kunt u mij vertellen hoe ik een reguliere expressie kan instellen om te controleren (er kan wel of geen overeenkomst zijn)?

Hoe u op de juiste manier een reguliere expressie schrijft die begint met het gelijkteken, de tekst erin vindt en stopt bij het &-teken
Deze karakters zijn niet opgenomen in de zoekopdracht die ermee begint en eindigt

noodzakelijk onderdeel

lijnen...

Ik schrijf op verschillende manieren, maar als resultaat blijft de hele tekst behouden, maar verdwijnen de = en & tekens
Of blijft de & aan het einde van de regel...

Ik las over de dollar, maar het teken aan het einde van de regel wordt niet verwijderd
klein voorbeeld
var reg = /[^=]*[^&]/g
Ik zou je heel dankbaar zijn) Hallo, vertel me hoe ik alle cijfers in moet vermelden deze uitdrukking door de ruimte 9*2 Goddelijk spiekbriefje! Alle vragen opgelost :-) (M1)
(M2)
(M3)
(M4)
(M5)

Vertel me hoe ik een uitdrukking moet schrijven om te achterhalen waar deze in de tekst voorkomt