Basisprincipes van reguliere expressies in C++

Regular Expression Basics C



Beschouw de volgende zin tussen aanhalingstekens:

'Hier is mijn man.'

Deze string kan zich in de computer bevinden en de gebruiker wil misschien weten of er het woord man in voorkomt. Als het het woord man heeft, wil hij misschien het woord man in vrouw veranderen; zodat de string zou moeten lezen:







'Hier is mijn vrouw.'

Er zijn nog veel meer van dit soort verlangens van de computergebruiker; sommige zijn ingewikkeld. Reguliere expressie, afgekort regex, is het onderwerp van de behandeling van deze problemen door de computer. C++ wordt geleverd met een bibliotheek genaamd regex. Een C++-programma voor het afhandelen van regex zou dus moeten beginnen met:



#erbij betrekken

#erbij betrekken

namespace std; gebruiken;

In dit artikel worden de basisprincipes van reguliere expressies in C++ uitgelegd.



Artikel Inhoud

Basisprincipes van reguliere expressies

Regex

Een string als Hier is mijn man. hierboven is de doelsequentie of doelreeks of eenvoudigweg doel. man, waarnaar werd gezocht, is de reguliere expressie, of eenvoudigweg, regex.





Bij elkaar passen

Er wordt gezegd dat er sprake is van matching wanneer het woord of de zin waarnaar wordt gezocht, wordt gevonden. Na matching kan er een vervanging plaatsvinden. Nadat de man zich erboven bevindt, kan deze bijvoorbeeld worden vervangen door de vrouw.

Eenvoudige Matching

Het volgende programma laat zien hoe het woord man wordt gevonden.



#erbij betrekken

#erbij betrekken

namespace std; gebruiken;

inthoofd()
{

regex reg('Mens');
indien (regex_search('Hier is mijn man.',reg))
kosten<< 'op elkaar afgestemd' <<eindel;
anders
kosten<< 'niet geëvenaard' <<eindel;

opbrengst 0;
}

De functie regex_search() retourneert true als er een overeenkomst is en retourneert false als er geen overeenkomst is. Hier heeft de functie twee argumenten: de eerste is de doeltekenreeks en de tweede is het regex-object. De regex zelf is 'man', tussen dubbele aanhalingstekens. De eerste instructie in de functie main() vormt het regex-object. Regex is een type en reg is het regex-object. De uitvoer van het bovenstaande programma is 'gematcht', aangezien 'man' wordt gezien in de doelreeks. Als 'man' niet werd gezien in het doel, zou regex_search() false hebben geretourneerd en zou de uitvoer 'niet overeenkomen' zijn geweest.

De uitvoer van de volgende code komt niet overeen:

regex reg('Mens');
indien (regex_search('Hier is mijn maaksel.',reg))
kosten<< 'op elkaar afgestemd' <<eindel;
anders
kosten<< 'niet geëvenaard' <<eindel;

Niet gevonden omdat de regex 'man' niet kon worden gevonden in de hele doelreeks, 'Hier is mijn maaksel'.

Patroon

De reguliere expressie, man hierboven, is heel eenvoudig. Regexes zijn meestal niet zo eenvoudig. Reguliere expressies hebben metatekens. Metakarakters zijn karakters met een speciale betekenis. Een metakarakter is een karakter over karakters. C++ regex-metatekens zijn:

^$ .* + ? ( ) [ ] { } |

Een regex, met of zonder metatekens, is een patroon.

Karakter klassen

Vierkante haakjes

Een patroon kan tekens tussen vierkante haken bevatten. Hiermee zou een bepaalde positie in de doelreeks overeenkomen met de tekens van de vierkante haken. Denk aan de volgende doelen:

'De kat is in de kamer.'

'De vleermuis is in de kamer.'

'De rat is in de kamer.'

De regex, [cbr]at zou overeenkomen met kat in het eerste doelwit. Het zou overeenkomen met bat in het tweede doel. Het zou overeenkomen met rat in het derde doelwit. Dit komt omdat kat of vleermuis of rat begint met 'c' of 'b' of 'r'. Het volgende codesegment illustreert dit:

regex reg('[cbr]at');
indien (regex_search('De kat is in de kamer.',reg))
kosten<< 'op elkaar afgestemd' <<eindel;
indien (regex_search('De vleermuis is in de kamer.',reg))
kosten<< 'op elkaar afgestemd' <<eindel;
indien (regex_search('De rat is in de kamer.',reg))
kosten<< 'op elkaar afgestemd' <<eindel;

De uitvoer is:

op elkaar afgestemd

op elkaar afgestemd

op elkaar afgestemd

Bereik van tekens

De klasse, [cbr] in het patroon [cbr], zou overeenkomen met verschillende mogelijke tekens in het doel. Het zou overeenkomen met 'c' of 'b' of 'r' in het doel. Als het doelwit geen 'c' of 'b' of 'r' heeft, gevolgd door at, zou er geen overeenkomst zijn.

Sommige mogelijkheden zoals 'c' of 'b' of 'r' bestaan ​​in een bereik. Het bereik van cijfers, 0 tot 9 heeft 10 mogelijkheden, en het patroon daarvoor is [0-9]. Het bereik van kleine letters, a tot z, heeft 26 mogelijkheden, en het patroon daarvoor is [a-z]. Het bereik van hoofdletters, A tot Z, heeft 26 mogelijkheden, en het patroon daarvoor is [A-Z]. – is officieel geen metateken, maar tussen vierkante haken zou het een bereik aangeven. Het volgende levert dus een match op:

indien (regex_search('ID6id',regex('[0-9]')))

kosten<< 'op elkaar afgestemd' <<eindel;

Merk op hoe de regex is geconstrueerd als het tweede argument. De overeenkomst vindt plaats tussen het cijfer, 6 in het bereik, 0 tot 9, en de 6 in het doel, ID6id. De bovenstaande code is gelijk aan:

indien (regex_search('ID6id',regex('[0123456789]')))

kosten<< 'op elkaar afgestemd' <<eindel;

De volgende code levert een overeenkomst op:

charP[] = 'ID6iE';

indien (regex_search(P,regex('[a-z]')))

kosten<< 'op elkaar afgestemd' <<eindel;

Merk op dat het eerste argument hier een stringvariabele is en niet de letterlijke string. De match is tussen 'i' in [a-z] en 'i' in ID6iE.

Vergeet niet dat een bereik een klasse is. Er kan tekst rechts van het bereik of links van het bereik in het patroon staan. De volgende code levert een overeenkomst op:

indien (regex_search('ID2id' is een identiteitsbewijs',regex('ID[0-9]id')))

kosten<< 'op elkaar afgestemd' <<eindel;

De overeenkomst is tussen ID[0-9]id en ID2id. De rest van de doelstring, is een ID, komt in deze situatie niet overeen.

Zoals gebruikt in het reguliere expressie-onderwerp (regexes), betekent het woord klasse eigenlijk een set. Dat wil zeggen, een van de personages in de set moet overeenkomen.

Opmerking: het koppelteken – is alleen een metateken tussen vierkante haken en geeft een bereik aan. Het is geen metateken in de regex, buiten de vierkante haken.

Negatie

Een klasse met een bereik kan worden genegeerd. Dat wil zeggen, geen van de tekens in de set (klasse) mag overeenkomen. Dit wordt aangegeven met het metateken ^ aan het begin van het klassenpatroon, net na het vierkante haakje dat begint. Dus [^0-9] betekent overeenkomen met het teken op de juiste positie in het doel, wat geen teken in het bereik is, inclusief 0 tot en met 9. Dus de volgende code zal geen overeenkomst opleveren:

indien (regex_search('0123456789101112',regex('[^ 0-9]')))

kosten<< 'op elkaar afgestemd' <<eindel;

anders

kosten<< 'niet geëvenaard' <<eindel;

Een cijfer binnen het bereik van 0 tot 9 kan worden gevonden in een van de doeltekenreeksposities, 0123456789101112,; dus er is geen overeenkomst - ontkenning.

De volgende code levert een overeenkomst op:

indien (regex_search('ABCDEFGHIJ',regex('[^ 0-9]')))

kosten<< 'op elkaar afgestemd' <<eindel;

Er kon geen cijfer worden gevonden in het doel, ABCDEFGHIJ,; dus er is een match.

[a-z] is een bereik buiten [^a-z]. En dus [^a-z] is de ontkenning van [a-z].

[A-Z] is een bereik buiten [^A-Z]. En dus [^A-Z] is de ontkenning van [A-Z].

Er zijn andere ontkenningen.

Overeenkomende witruimtes

‘ ’ of of of of f is een spatieteken. In de volgende code komt de regex, overeen met ' ' in het doel:

indien (regex_search('Van lijn één.RNVan lijn twee.',regex('N')))

kosten<< 'op elkaar afgestemd' <<eindel;

Overeenkomen met elk witruimteteken

Het patroon of de klasse die overeenkomt met een witruimteteken is [ f]. In de volgende code komt ‘ ’ overeen:

indien (regex_search('een twee',regex('[ RNF] ')))

kosten<< 'op elkaar afgestemd' <<eindel;

Overeenkomen met elk niet-witruimteteken

Het patroon of de klasse die overeenkomt met elk niet-witruimteteken is [^ f]. De volgende code produceert een overeenkomst omdat er geen witruimte in het doel is:

indien (regex_search('1234abcd',regex('[^ RNF] ')))

kosten<< 'op elkaar afgestemd' <<eindel;

De punt (.) in het patroon

De punt (.) in het patroon komt overeen met elk teken, inclusief zichzelf, behalve , in het doel. Een match wordt geproduceerd in de volgende code:

indien (regex_search('1234abcd',regex('.')))

kosten<< 'op elkaar afgestemd' <<eindel;

Geen overeenkomende resultaten in de volgende code omdat het doel is.

indien (regex_search('N',regex('.')))

kosten<< 'op elkaar afgestemd' <<eindel;

anders

kosten<< 'niet geëvenaard' <<eindel;

Opmerking: binnen een tekenklasse met vierkante haken heeft de punt geen speciale betekenis.

Overeenkomende herhalingen

Een teken of een groep tekens kan meer dan één keer voorkomen binnen de doelreeks. Een patroon kan deze herhaling evenaren. De metatekens, ?, *, + en {} worden gebruikt om de herhaling in het doel te matchen. Als x een interessant teken is in de doelreeks, hebben de metatekens de volgende betekenis:

x*:betekent overeenkomen'x' 0of meerdere keren,l.En.,een willekeurig aantal keren

x+:betekent overeenkomen'x' 1of meerdere keren,l.En.,ten minste een keer

x? :betekent overeenkomen'x' 0of1 tijd

x{N,}:betekent overeenkomen'x'minstens n of meer keer.Opmerkingde komma.

x{N} :bij elkaar passen'x'precies n keer

x{N,m}:bij elkaar passen'x'minstens n keer,maar niet meer dan m keer.

Deze metatekens heten kwantoren.

Illustraties

*

De * komt overeen met het voorgaande teken of de voorgaande groep, nul of meer keer. o* komt overeen met 'o' in dog van de doelreeks. Het komt ook overeen met oo in boek en kijken. De regex, o* komt overeen met boooo in The animal booooed.. Opmerking: o* komt overeen met dig, waarbij 'o' nul (of meer) tijd voorkomt.

+

De + komt 1 of meer keer overeen met het voorgaande teken of de voorgaande groep. Vergelijk het met nul of meer keer voor *. Dus de regex, e+ komt overeen met 'e' in eat, waarbij 'e' één keer voorkomt. e+ komt ook overeen met ee bij schapen, waar 'e' meer dan één keer voorkomt. Opmerking: e+ komt niet overeen met dig omdat in dig 'e' niet minstens één keer voorkomt.

?

De ? komt overeen met het voorgaande teken of de voorgaande groep, 0 of 1 keer (en niet meer). Dus, e? komt overeen met dig omdat 'e' voorkomt in dig, nul tijd. e? komt overeen met set omdat 'e' één keer in set voorkomt. Let op: e? komt nog steeds overeen met schapen; hoewel er twee 'e's bij schapen zijn. Er is hier een nuance - zie later.

{N,}

Dit komt overeen met ten minste n opeenvolgende herhalingen van een voorafgaand teken of voorgaande groep. Dus de regex, e{2,} komt overeen met de twee 'e's in het doel, schapen, en de drie 'e's in het doelschaap. e{2,} komt niet overeen met set, omdat set maar één 'e' heeft.

{N}

Dit komt overeen met exact n opeenvolgende herhalingen van een voorafgaand teken of voorgaande groep. Dus de regex, e{2} komt overeen met de twee 'e's in het doel, schapen. e{2} komt niet overeen met set omdat set maar één 'e' heeft. Nou, e{2} komt overeen met twee 'e's in het doelwit, schaap. Er is hier een nuance - zie later.

{n,m}

Dit komt overeen met meerdere opeenvolgende herhalingen van een voorafgaand teken of voorgaande groep, overal van n tot en met m. Dus e{1,3} komt met niets overeen in dig, dat geen 'e' heeft. Het komt overeen met de ene 'e' in set, de twee 'e's in sheep, de drie 'e's in sheep, en drie 'e's in sheepee'. Er is een nuance bij de laatste wedstrijd - zie later.

Bijpassende afwisseling

Beschouw de volgende doelreeks in de computer.

De boerderij heeft varkens van verschillende groottes.

De programmeur wil misschien weten of dit doelwit een geit, een konijn of een varken heeft. De code zou als volgt zijn:

charP[] = 'De boerderij heeft varkens van verschillende grootte.';

indien (regex_search(P,regex('geit|konijn|varken')))

kosten<< 'op elkaar afgestemd' <<eindel;

anders

kosten<< 'niet geëvenaard' <<eindel;

De code levert een match op. Let op het gebruik van het afwisselingsteken, |. Er kunnen twee, drie, vier en meer opties zijn. C++ zal eerst proberen het eerste alternatief, geit, te matchen op elke tekenpositie in de doelreeks. Lukt het niet met geit, dan probeert het het volgende alternatief, konijn. Lukt het niet met konijn, dan probeert het het volgende alternatief, varken. Als pig faalt, gaat C++ verder naar de volgende positie in het doel en begint opnieuw met het eerste alternatief.

In de bovenstaande code is varken gematcht.

Overeenkomend begin of einde

Begin


Als ^ aan het begin van de regex staat, kan de begintekst van de doelreeks worden vergeleken met de regex. In de volgende code is het begin van het doel abc, wat overeenkomt:

indien (regex_search('abc en def',regex('^ abc')))

kosten<< 'op elkaar afgestemd' <<eindel;

Er vindt geen matching plaats in de volgende code:

indien (regex_search('Ja, abc en def',regex('^ abc')))

kosten<< 'op elkaar afgestemd' <<eindel;

anders

kosten<< 'niet geëvenaard' <<eindel;

Hier staat abc niet aan het begin van het doel.

Opmerking: het circumflex-teken, '^', is een metateken aan het begin van de regex, overeenkomend met het begin van de doelreeks. Het is nog steeds een metakarakter aan het begin van de karakterklasse, waar het de klasse negeert.

Einde

Als $ aan het einde van de regex staat, kan de eindtekst van de doelreeks worden vergeleken met de regex. In de volgende code is het einde van het doel xyz, wat overeenkomt:

indien (regex_search('uvw en xyz',regex('xyz$')))

kosten<< 'op elkaar afgestemd' <<eindel;

Er vindt geen matching plaats in de volgende code:

indien (regex_search('uvw en xyz finale',regex('xyz$')))

kosten<< 'op elkaar afgestemd' <<eindel;

anders

kosten<< 'niet geëvenaard' <<eindel;

Hier bevindt xyz zich niet aan het einde van het doel.

Groepering

Haakjes kunnen worden gebruikt om tekens in een patroon te groeperen. Overweeg de volgende regex:

'een concert (pianist)'

De groep hier is pianist omringd door de metakarakters ( en ). Het is eigenlijk een subgroep, terwijl een concert (pianist) de hele groep is. Stel je de volgende situatie voor:

'De (pianist is goed)'

Hier, de subgroep of substring is, pianist is goed.

Sub-strings met Common Parts

Een boekhouder is iemand die voor boeken zorgt. Stel je een bibliotheek voor met een boekhouder en boekenplank. Neem aan dat een van de volgende doelreeksen zich in de computer bevindt:

'De bibliotheek heeft een boekenplank die bewonderd wordt.';

'Hier is de boekhouder.';

'De boekhouder werkt met de boekenplank.';

Neem aan dat de programmeur er niet in geïnteresseerd is om te weten welke van deze zinnen in de computer staat. Toch is zijn interesse om te weten of een boekenplank of boekhouder aanwezig is in de doelreeks op de computer. In dit geval kan zijn regex zijn:

'boekenplank|boekhouder.'

Afwisseling gebruiken.

Merk op dat het boek, dat beide woorden gemeen hebben, twee keer is getypt, in de twee woorden in het patroon. Om te voorkomen dat je boek twee keer typt, kan de regex beter worden geschreven als:

'boek(plank|houder)'

Hier, de groep, schapbewaarder Het metakarakter van de afwisseling is nog steeds gebruikt, maar niet voor twee lange woorden. Het is gebruikt voor de twee einddelen van de twee lange woorden. C++ behandelt een groep als een entiteit. Dus C++ zoekt naar een plank of houder die direct na het boek komt. De uitvoer van de volgende code komt overeen:

charP[] = 'De bibliotheek heeft een boekenplank die bewonderd wordt.';

indien (regex_search(P,regex('boek(plank|houder)')))

kosten<< 'op elkaar afgestemd' <<eindel;

boekenplank en niet boekhouder zijn gematcht.

De icase en multiline regex_constants

icase

Matching is standaard hoofdlettergevoelig. Het kan echter hoofdletterongevoelig worden gemaakt. Gebruik hiervoor de regex::icase-constante, zoals in de volgende code:

indien (regex_search('Feedback',regex('voeden',regex::icase)))

kosten<< 'op elkaar afgestemd' <<eindel;

De output komt overeen. Dus feedback met hoofdletter 'F' is gekoppeld aan feed met kleine letter 'f'. regex::icase is gemaakt tot het tweede argument van de regex() constructor. Zonder dat zou de verklaring geen overeenkomst opleveren.

Multilijn

Beschouw de volgende code:

charP[] = 'lijn 1Nlijn 2Nlijn 3';

indien (regex_search(P,regex('^. * $')))

kosten<< 'op elkaar afgestemd' <<eindel;

anders

kosten<< 'niet geëvenaard' <<eindel;

De output komt niet overeen. De regex, ^.*$, komt overeen met de doelreeks van het begin tot het einde. .* betekent elk teken behalve , nul of meer keer. Dus vanwege de nieuwe regeltekens ( ) in het doel was er geen overeenkomst.

Het doel is een tekenreeks met meerdere regels. Om ervoor te zorgen dat ‘.’ overeenkomt met het teken van de nieuwe regel, moet de constante regex::multiline worden gemaakt, het tweede argument van de regex()-constructie. De volgende code illustreert dit:

charP[] = 'lijn 1Nlijn 2Nlijn 3';

indien (regex_search(P,regex('^. * $',regex::multilijn)))

kosten<< 'op elkaar afgestemd' <<eindel;

anders

kosten<< 'niet geëvenaard' <<eindel;

Overeenkomen met de hele doelreeks

Om de hele doelstring te matchen, die niet het newline-teken ( ) heeft, kan de functie regex_match() worden gebruikt. Deze functie verschilt van regex_search(). De volgende code illustreert dit:

charP[] = 'eerste tweede derde';

indien (regex_match(P,regex('.*tweede.*')))

kosten<< 'op elkaar afgestemd' <<eindel;

Hier is een wedstrijd. Houd er echter rekening mee dat de regex overeenkomt met de hele doelreeks en dat de doelreeks geen ' ' heeft.

Het match_results-object

De functie regex_search() kan een argument opnemen tussen het doel en het regex-object. Dit argument is het object match_results. De hele gematchte (deel)string en de gematchte substrings kunnen ermee bekend zijn. Dit object is een speciale array met methoden. Het objecttype match_results is cmatch (voor letterlijke tekenreeksen).

Matches verkrijgen

Beschouw de volgende code:

charP[] = 'De vrouw die je zocht!';

match m;

indien (regex_search(P,m,regex('w.m.n')))

kosten<<m[0] <<eindel;

De doelstring heeft het woord vrouw. De output is woman’, wat overeenkomt met de regex, w.m.n. Bij index nul bevat de speciale array de enige match, namelijk vrouw.

Met klasse-opties wordt alleen de eerste substring die in het doel wordt gevonden, naar de speciale array verzonden. De volgende code illustreert dit:

match m;

indien (regex_search('De rat, de kat, de vleermuis!',m,regex('[bcr]at')))

kosten<<m[0] <<eindel;

kosten<<m[1] <<eindel;

kosten<<m[2] <<eindel;

De output is rat vanaf index nul. m[1] en m[2] zijn leeg.

Bij alternatieven wordt alleen de eerste substring die in het doel wordt gevonden, naar de speciale array gestuurd. De volgende code illustreert dit:

indien (regex_search('Het konijn, de geit, het varken!',m,regex('geit|konijn|varken')))

kosten<<m[0] <<eindel;

kosten<<m[1] <<eindel;

kosten<<m[2] <<eindel;

De uitvoer is konijn vanaf index nul. m[1] en m[2] zijn leeg.

Groeperingen

Wanneer er groepen bij betrokken zijn, gaat het volledige patroon dat overeenkomt, in cel nul van de speciale array. De volgende gevonden substring gaat naar cel 1; de substring die volgt, gaat naar cel 2; enzovoort. De volgende code illustreert dit:

indien (regex_search('Beste boekhandelaar vandaag!',m,regex('boek ((sel) (ler))')))

kosten<<m[0] <<eindel;

kosten<<m[1] <<eindel;

kosten<<m[2] <<eindel;

kosten<<m[3] <<eindel;

De uitvoer is:

boekhandelaar

verkoper

cel

lezen

Merk op dat de groep (verkoper) vóór de groep (sel) komt.

Positie van wedstrijd

De positie van match voor elke substring in de cmatch-array kan bekend zijn. Het tellen begint vanaf het eerste teken van de doelreeks, op positie nul. De volgende code illustreert dit:

match m;

indien (regex_search('Beste boekhandelaar vandaag!',m,regex('boek ((sel) (ler))')))

kosten<<m[0] << '->' <<m.positie(0) <<eindel;

kosten<<m[1] << '->' <<m.positie(1) <<eindel;

kosten<<m[2] << '->' <<m.positie(2) <<eindel;

kosten<<m[3] << '->' <<m.positie(3) <<eindel;

Let op het gebruik van de eigenschap position, met de celindex, als argument. De uitvoer is:

boekhandelaar->5

verkoper->9

cel->9

lezen->12

Zoeken en vervangen

Een nieuw woord of nieuwe zin kan de overeenkomst vervangen. Hiervoor wordt de functie regex_replace() gebruikt. Deze keer is de tekenreeks waar de vervanging plaatsvindt echter het tekenreeksobject, niet de letterlijke tekenreeks. De stringbibliotheek moet dus in het programma worden opgenomen. Illustratie:

#erbij betrekken

#erbij betrekken

#erbij betrekken

namespace std; gebruiken;

inthoofd()
{
tekenreeks= 'Hier, komt mijn man. Daar gaat je man.';
string newStr=regex_replace(P,regex('Mens'), 'vrouw');
kosten<<nieuweStr<<eindel;

opbrengst 0;
}

De functie regex_replace(), zoals hier gecodeerd, vervangt alle overeenkomsten. Het eerste argument van de functie is het doel, het tweede is het regex-object en het derde is de vervangende tekenreeks. De functie retourneert een nieuwe tekenreeks, die het doel is maar de vervanging heeft. De uitvoer is:

Hier komt mijn vrouw. Daar gaat je vrouw.

Conclusie

De reguliere expressie gebruikt patronen om subtekenreeksen in de doelreeksreeks te matchen. Patronen hebben metakarakters. Veelgebruikte functies voor C++ reguliere expressies zijn: regex_search(), regex_match() en regex_replace(). Een regex is een patroon tussen dubbele aanhalingstekens. Deze functies nemen echter het regex-object als argument en niet alleen de regex. Van de regex moet een regex-object worden gemaakt voordat deze functies het kunnen gebruiken.