Osnove regularnih izrazov v C ++

Regular Expression Basics C



Razmislite o naslednjem stavku v narekovajih:

'Tukaj je moj mož.'

Ta niz je morda v računalniku in uporabnik bo morda želel vedeti, ali vsebuje besedo man. Če ima besedo moški, bo morda želel besedo moški spremeniti v žensko; tako da naj bi se niz glasil:







'Tukaj je moja ženska.'

Obstaja še veliko drugih želja, kot so te od uporabnika računalnika; nekateri so zapleteni. Regular Expression, skrajšano regex, je predmet obravnave teh težav z računalnikom. C ++ ima knjižnico z imenom regex. Torej, program C ++ za obravnavo regexa se mora začeti z:



#vključi

#vključi

z uporabo imenskega prostora std;

Ta članek pojasnjuje osnove pravilnega izražanja v C ++.



Vsebina članka

Osnove rednega izražanja

Regex

Vrvica, kot je Here is my man. zgoraj je ciljno zaporedje ali ciljni niz ali preprosto cilj. man, ki so ga iskali, je regularni izraz ali preprosto regex.





Ujemanje

Do ujemanja naj bi prišlo, ko se najde beseda ali stavek, ki ga iščete. Po ujemanju lahko pride do zamenjave. Na primer, potem ko se moški nahaja zgoraj, ga lahko nadomesti ženska.

Enostavno ujemanje

Naslednji program prikazuje, kako se beseda človek ujema.



#vključi

#vključi

z uporabo imenskega prostora std;

intglavni()
{

regex reg('človek');
če (regex_search('Tukaj je moj mož.',reg))
stroški<< 'ujeto' <<endl;
drugače
stroški<< 'se ne ujema' <<endl;

vrnitev 0;
}

Funkcija regex_search () vrne true, če obstaja ujemanje in vrne false, če ni ujemanja. Tu funkcija sprejme dva argumenta: prvi je ciljni niz, drugi pa predmet regex. Regex je v dvojnih narekovajih 'človek'. Prvi stavek v funkciji main () tvori regex objekt. Regex je vrsta, reg pa predmet regex. Izhod zgornjega programa se 'ujema', saj je v ciljnem nizu viden 'man'. Če 'man' ni bil viden v cilju, bi regex_search () vrnil false, izhod pa bi bil 'not match'.

Izhod te kode se ne ujema:

regex reg('človek');
če (regex_search('Tukaj je moje ustvarjanje.',reg))
stroški<< 'ujeto' <<endl;
drugače
stroški<< 'se ne ujema' <<endl;

Ni ujemanje, ker regexa 'man' ni mogoče najti v celotnem ciljnem nizu, 'Here is my making.'

Vzorec

Redni izraz, človek zgoraj, je zelo preprost. Regeksi običajno niso tako preprosti. Regularni izrazi imajo metaznake. Metaznaki so znaki s posebnim pomenom. Metaznak je lik o likih. Metaznaki regex C ++ so:

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

Regex z ali brez metaznakov je vzorec.

Razredi znakov

Oglati oklepaji

Vzorec ima lahko znake v oglatih oklepajih. S tem bi se določeno mesto v ciljnem nizu ujemalo s katerim koli znakom v oglatih oklepajih. Upoštevajte naslednje cilje:

'Mačka je v sobi.'

'Netopir je v sobi.'

'Podgana je v sobi.'

Regex, [cbr] at bi se ujemal z mačko v prvi tarči. V drugi tarči bi se ujemal z netopirjem. Ujemal bi se s podgano v tretji tarči. To je zato, ker se mačka, netopir ali podgana začne z 'c' ali 'b' ali 'r'. Naslednji kodni segment to ponazarja:

regex reg('[cbr] ob');
če (regex_search('Mačka je v sobi.',reg))
stroški<< 'ujeto' <<endl;
če (regex_search('Netopir je v sobi.',reg))
stroški<< 'ujeto' <<endl;
če (regex_search('Podgana je v sobi.',reg))
stroški<< 'ujeto' <<endl;

Izhod je:

ujemajo

ujemajo

ujemajo

Obseg znakov

Razred [cbr] v vzorcu [cbr] bi se ujemal z več možnimi znaki v tarči. To bi se ujemalo z 'c' ali 'b' ali 'r' v cilju. Če tarča nima nobenega od 'c' ali 'b' ali 'r', ki mu sledi at, ne bo ujemanja.

Nekatere možnosti, na primer 'c' ali 'b' ali 'r', obstajajo v razponu. Obseg števk od 0 do 9 ima 10 možnosti, vzorec za to pa je [0-9]. Obseg malih črk, od a do z, ima 26 možnosti, vzorec za to pa je [a-z]. Obseg velikih črk od A do Ž ima 26 možnosti, vzorec za to pa je [A-Z]. - uradno ni metaznak, vendar bi v oglatih oklepajih označeval obseg. Tako se ujema z naslednjim:

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

stroški<< 'ujeto' <<endl;

Upoštevajte, kako je bil regex zgrajen kot drugi argument. Ujema se med števko, 6 v razponu, od 0 do 9, in 6 v tarči, ID6id. Zgornja koda je enakovredna:

če (regex_search('ID6id',regex('[0123456789]')))

stroški<< 'ujeto' <<endl;

Naslednja koda ustvari ujemanje:

charstr[] = 'ID6iE';

če (regex_search(str,regex('[a-z]')))

stroški<< 'ujeto' <<endl;

Upoštevajte, da je prvi argument spremenljivka niza in ne literal niza. Ujemanje je med 'i' v [a-z] in 'i' v ID6iE.

Ne pozabite, da je obseg razred. Besedilo je lahko desno od obsega ali levo od obsega v vzorcu. Naslednja koda ustvari ujemanje:

če (regex_search('ID2id je osebna izkaznica ',regex('ID [0-9] id')))

stroški<< 'ujeto' <<endl;

Ujema se med ID [0-9] id in ID2id. Preostanek ciljnega niza, je ID, se v tem primeru ne ujema.

Kot se uporablja v subjektu regularnega izraza (regexes), beseda class dejansko pomeni niz. To pomeni, da se eden od likov v nizu ujema.

Opomba: vezaj - je metaznak samo v oglatih oklepajih, ki označuje obseg. To ni metaznak v regularnem izrazu, izven oglatih oklepajev.

Negacija

Razred, ki vključuje obseg, je mogoče zanikati. To pomeni, da se noben od znakov v nizu (razredu) ne bi smel ujemati. To je označeno z metaznakom ^ na začetku vzorca razreda, tik za začetnim oglatim oklepajem. Torej [^0-9] pomeni ujemanje znaka na ustreznem mestu v tarči, ki ni kateri koli znak v obsegu, vključno od 0 do 9. Naslednja koda se torej ne bo ujemala:

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

stroški<< 'ujeto' <<endl;

drugače

stroški<< 'se ne ujema' <<endl;

Številko v razponu od 0 do 9 je mogoče najti v katerem koli položaju ciljnega niza, 0123456789101112 ,; torej ni ujemanja - negacije.

Naslednja koda ustvari ujemanje:

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

stroški<< 'ujeto' <<endl;

V tarči ni bilo mogoče najti nobene številke, ABCDEFGHIJ ,; torej obstaja ujemanje.

[a-z] je obseg zunaj [^a-z]. In tako je [^a-z] negacija [a-z].

[A-Z] je območje zunaj [^A-Z]. In tako je [^A-Z] negacija [A-Z].

Obstajajo tudi druge negacije.

Ujemanje presledkov

‘’ Ali t ali r ali n ali f je presledek. V naslednji kodi se regex n ujema z ' n' v cilju:

če (regex_search('Prva vrstica. r nDruge vrstice. ',regex(' n')))

stroški<< 'ujeto' <<endl;

Ujemanje s katerim koli presledkom

Vzorec ali razred, ki se ujema s katerim koli presledkom, je [ t r n f]. V naslednji kodi se ujema '':

če (regex_search('en dva',regex('[ t r n f] ')))

stroški<< 'ujeto' <<endl;

Ujemanje s katerim koli znakom, ki ni prazen

Vzorec ali razred, ki se ujema s katerim koli znakom, ki ni prazen, je [^ t r n f]. Naslednja koda ustvari ujemanje, ker v cilju ni presledkov:

če (regex_search('1234abcd',regex('[^ t r n f] ')))

stroški<< 'ujeto' <<endl;

Točka (.) V vzorcu

Točka (.) V vzorcu se ujema s katerim koli znakom, vključno s samim seboj, razen n, v cilju. Ujemanje se ustvari v naslednji kodi:

če (regex_search('1234abcd',regex('.')))

stroški<< 'ujeto' <<endl;

V naslednji kodi ni ujemajočih se rezultatov, ker je cilj n.

če (regex_search(' n',regex('.')))

stroški<< 'ujeto' <<endl;

drugače

stroški<< 'se ne ujema' <<endl;

Opomba: Znotraj razreda znakov s kvadratnimi oklepaji pika nima posebnega pomena.

Ujemanje ponovitev

Znak ali skupina znakov se lahko v ciljnem nizu pojavi več kot enkrat. Vzorec se lahko ujema s to ponovitvijo. Metaznaki,?, *, +In {} se uporabljajo za ujemanje ponavljanja v cilju. Če je x ciljni znak v ciljnem nizu, imajo metaznaki naslednji pomen:

x*:pomeni ujemanje'x' 0ali večkrat,jaz.In.,poljubno število krat

x+:pomeni ujemanje'x' 1ali večkrat,jaz.In.,vsaj enkrat

x? :pomeni ujemanje'x' 0ali1 čas

x{n,}:pomeni ujemanje'x'vsaj n ali večkrat.Opombavejica.

x{n} :ujemati'x'točno n -krat

x{n,m}:ujemati'x'vsaj n krat,vendar ne več kot m krat.

Ti metaznaki se imenujejo količniki.

Ilustracije

*

* Se ujema s prejšnjim znakom ali prejšnjo skupino, nič ali večkrat. o* se ujema z 'o' v pasu ciljnega niza. Prav tako se ujema z oo v knjigi in iskanju. Regex, o* se ujema z boooo v Animal booooed .. Opomba: o* se ujema z dig, kjer se 'o' pojavi nič (ali več) časa.

+

+ Se ujema s prejšnjim znakom ali prejšnjo skupino, 1 ali večkrat. Primerjajte z ničlo ali večkrat za *. Tako se regex, e+ ujema z „e“ v prehrani, kjer se enkrat pojavi „e“. e+ se ujema tudi z ee pri ovcah, kjer se 'e' pojavlja večkrat. Opomba: e+ se ne bo ujemal z dig, ker se v dig 'e' ne pojavi vsaj enkrat.

?

The? se ujema s prejšnjim znakom ali prejšnjo skupino, 0 ali 1 -krat (in ne več). Torej, e? ujema dig, ker se v dig pojavi 'e', nič časa. e? se ujema, ker se v nizu enkrat pojavi »e«. Opomba: e? še vedno ustreza ovcam; čeprav sta pri ovcah dva 'e'. Tu je odtenek - glej kasneje.

{n,}

To ustreza najmanj n zaporednim ponovitvam predhodnega znaka ali prejšnje skupine. Tako se regex, e {2,} ujema z dvema „e“ v tarči, ovcami in tremi „e“ v ciljnem ovcu. e {2,} se ne ujema z nizom, ker ima niz samo eno 'e'.

{n}

To ustreza natanko n zaporednim ponovitvam predhodnega znaka ali prejšnje skupine. Tako se regex, e {2} ujema z dvema 'e' v tarči, ovce. e {2} se ne ujema z nizom, ker ima niz samo eno 'e'. No, e {2} se ujema z dvema 'e' v tarči, ovce. Tu je odtenek - glej kasneje.

{n, m}

To se ujema z več zaporednimi ponovitvami predhodnega znaka ali predhodne skupine, kjer koli od n do vključno vključno. Torej se e {1,3} nič ne ujema z dig, ki nima 'e'. Ujema se z enim 'e' v nizu, dvema 'e' v ovcah, tremi 'e' v ovcah in tremi 'e' v ovcah. Na zadnji tekmi je odtenek - glej kasneje.

Ujemanje alternacije

Razmislite o naslednjem ciljnem nizu v računalniku.

Na kmetiji so prašiči različnih velikosti.

Programer bo morda želel vedeti, ali ima ta tarča kozo, zajca ali prašiča. Koda bi bila naslednja:

charstr[] = 'Na kmetiji so prašiči različnih velikosti.';

če (regex_search(str,regex('koza | zajec | prašič')))

stroški<< 'ujeto' <<endl;

drugače

stroški<< 'se ne ujema' <<endl;

Koda ustvari ujemanje. Upoštevajte uporabo znaka za zamenjavo, |. Možnosti so lahko dve, tri, štiri in več. C ++ se bo najprej poskušal ujemati s prvo alternativo, kozjo, na vsakem položaju znakov v ciljnem nizu. Če s kozo ne uspe, poskusi z naslednjo alternativo, zajcem. Če s kuncem ne uspe, poskusi z naslednjo alternativo, prašičem. Če prašič ne uspe, se C ++ premakne na naslednje mesto v tarči in znova začne s prvo alternativo.

V zgornji kodi se prašič ujema.

Ujemanje začetka ali konca

Začetek


Če je ^ na začetku regeksa, se lahko regex ujema z začetnim besedilom ciljnega niza. V naslednji kodi je začetek cilja abc, ki se ujema:

če (regex_search('abc in def',regex('^ abc')))

stroški<< 'ujeto' <<endl;

V naslednji kodi ni ujemanja:

če (regex_search('Da, abc in def',regex('^ abc')))

stroški<< 'ujeto' <<endl;

drugače

stroški<< 'se ne ujema' <<endl;

Tu abc ni na začetku cilja.

Opomba: Circuflex znak '^' je metaznak na začetku regeksa, ki se ujema z začetkom ciljnega niza. Še vedno je metaznak na začetku razreda znakov, kjer razred zanika.

Konec

Če je $ na koncu regeksa, se lahko regex ujema s končnim besedilom ciljnega niza. V naslednji kodi je konec cilja xyz, ki se ujema:

če (regex_search('uvw in xyz',regex('xyz $')))

stroški<< 'ujeto' <<endl;

V naslednji kodi ni ujemanja:

če (regex_search('uvw in xyz final',regex('xyz $')))

stroški<< 'ujeto' <<endl;

drugače

stroški<< 'se ne ujema' <<endl;

Tukaj xyz ni na koncu cilja.

Združevanje

Oklepaji se lahko uporabljajo za združevanje znakov v vzorec. Upoštevajte naslednji regex:

'koncert (pianist)'

Skupina je pianistka, obdana z metaznaki (in). Pravzaprav je podskupina, medtem ko je koncert (pianist) celotna skupina. Upoštevajte naslednje:

'(Pianist je dober)'

Tu je podskupina ali podniz: pianist je dober.

Podniz z običajnimi deli

Knjigovodja je oseba, ki skrbi za knjige. Predstavljajte si knjižnico z knjigovodjo in knjižno polico. Predpostavimo, da je v računalniku eden od naslednjih ciljnih nizov:

'Knjižnica ima knjižno polico, ki jo občudujemo.';

'Tukaj je knjigovodja.';

'Knjigovodja dela s knjižno polico.';

Predpostavimo, da programerjev interes ni vedeti, kateri od teh stavkov je v računalniku. Kljub temu ga zanima, ali je knjižna polica ali knjigovodja prisotna v katerem koli ciljnem nizu v računalniku. V tem primeru je njegov regex lahko:

'knjižna polica | knjigovodja.'

Uporaba alternacije.

Upoštevajte, da je bila knjiga, ki je skupna obema besedama, dvakrat vtipkana v dveh besedah ​​v vzorcu. Da se izognete dvakratnemu tipkanju knjige, bi bilo regex bolje zapisati tako:

'knjiga (polica | imetnik)'

Tu je skupina, polica | imetnik nadomestnega metaznaka je bil še vedno uporabljen, vendar ne za dve dolgi besedi. Uporabljali so ga za dva zaključna dela dveh dolgih besed. C ++ obravnava skupino kot entiteto. Tako bo C ++ poiskal polico ali imetnika, ki pride takoj po knjigi. Izhod naslednje kode se ujema:

charstr[] = 'Knjižnica ima knjižno polico, ki jo občudujemo.';

če (regex_search(str,regex('knjiga (polica | imetnik)')))

stroški<< 'ujeto' <<endl;

knjižna polica in ne knjigovodja sta se ujemala.

Icase in multiline regex_constants

icase

Ujemanje privzeto razlikuje velike in male črke. Lahko pa ga naredimo neobčutljivega na velike in male črke. Če želite to narediti, uporabite konstanto regex :: icase, kot v naslednji kodi:

če (regex_search('Povratne informacije',regex('krma',regex::icase)))

stroški<< 'ujeto' <<endl;

Izhod se ujema. Tako se povratne informacije z velikimi črkami 'F' ujemajo z virom z malimi črkami 'f'. regex :: icase je bil drugi argument konstruktorja regex (). Brez tega se izjava ne bi ujemala.

Multiline

Upoštevajte naslednjo kodo:

charstr[] = 'vrstica 1 nvrstica 2 nvrstica 3 ';

če (regex_search(str,regex('^. * $')))

stroški<< 'ujeto' <<endl;

drugače

stroški<< 'se ne ujema' <<endl;

Izhod se ne ujema. Regex, ^.*$, Se ujema s ciljnim nizom od začetka do konca. .* pomeni kateri koli znak razen n, nič ali večkrat. Tako zaradi znakov nove vrstice ( n) v cilju ni bilo ujemanja.

Cilj je večvrstični niz. Da bi se '.' Ujemalo z znakom nove vrstice, je treba narediti konstantno regex :: multiline, drugi argument konstrukcije regex (). Naslednja koda ponazarja to:

charstr[] = 'vrstica 1 nvrstica 2 nvrstica 3 ';

če (regex_search(str,regex('^. * $',regex::večvrstično)))

stroški<< 'ujeto' <<endl;

drugače

stroški<< 'se ne ujema' <<endl;

Ujemanje niza celega cilja

Če želite ujemati celoten ciljni niz, ki nima znaka za novo vrstico ( n), lahko uporabite funkcijo regex_match (). Ta funkcija se razlikuje od regex_search (). Naslednja koda ponazarja to:

charstr[] = 'prvi drugi tretji';

če (regex_match(str,regex('.*drugi.*')))

stroški<< 'ujeto' <<endl;

Tukaj je ujemanje. Vendar upoštevajte, da se regex ujema s celotnim ciljnim nizom, ciljni niz pa nima ' n'.

Objekt match_results

Funkcija regex_search () lahko sprejme argument med ciljem in predmetom regex. Ta argument je objekt match_results. Z njim je mogoče poznati celoten ujemajoči se del (del) in ujemajoče se nizove. Ta predmet je posebna matrika z metodami. Vrsta predmeta match_results je cmatch (za literale niza).

Pridobitev tekem

Upoštevajte naslednjo kodo:

charstr[] = 'Ženska, ki ste jo iskali!';

cmatch m;

če (regex_search(str,m,regex('w.m.n')))

stroški<<m[0] <<endl;

Ciljni niz ima besedo ženska. Izhod je ženska, kar ustreza regularnemu izrazu, w.m.n. Pri indeksu nič ima posebna matrika edino ujemanje, to je ženska.

Z možnostmi razreda se v poseben niz pošlje samo prvi podniz, ki ga najdemo v cilju. Naslednja koda ponazarja to:

cmatch m;

če (regex_search('Podgana, mačka, netopir!',m,regex('[bcr] pri')))

stroški<<m[0] <<endl;

stroški<<m[1] <<endl;

stroški<<m[2] <<endl;

Izhod je podgana iz indeksa nič. m [1] in m [2] sta prazna.

Z drugimi možnostmi se v prvi niz pošlje samo prvi podniz, ki ga najdemo v cilju. Naslednja koda ponazarja to:

če (regex_search('Zajec, koza, prašič!',m,regex('koza | zajec | prašič')))

stroški<<m[0] <<endl;

stroški<<m[1] <<endl;

stroški<<m[2] <<endl;

Izhod je kunec iz indeksa nič. m [1] in m [2] sta prazna.

Združevanje v skupine

Ko so vključene skupine, se celoten vzorec ujema, gre v celico nič posebnega niza. Naslednji najdeni podniz je v celici 1; podniz, ki sledi, gre v celico 2; in tako naprej. Naslednja koda ponazarja to:

če (regex_search('Najboljši prodajalec knjig danes!',m,regex('book ((sel) (ler))')))

stroški<<m[0] <<endl;

stroški<<m[1] <<endl;

stroški<<m[2] <<endl;

stroški<<m[3] <<endl;

Izhod je:

knjigarna

prodajalec

celica

prebrati

Upoštevajte, da je skupina (prodajalec) pred skupino (sel).

Položaj tekme

Položaj ujemanja za vsak podniz v nizu cmatch je lahko znan. Odštevanje se začne od prvega znaka ciljnega niza na položaju nič. Naslednja koda ponazarja to:

cmatch m;

če (regex_search('Najboljši prodajalec knjig danes!',m,regex('book ((sel) (ler))')))

stroški<<m[0] << '->' <<mpoložaj(0) <<endl;

stroški<<m[1] << '->' <<mpoložaj(1) <<endl;

stroški<<m[2] << '->' <<mpoložaj(2) <<endl;

stroški<<m[3] << '->' <<mpoložaj(3) <<endl;

Upoštevajte uporabo lastnosti položaja z indeksom celic kot argument. Izhod je:

knjigarna->5

prodajalec->9

celica->9

prebrati->12

Išči in zamenjaj

Nova beseda ali stavek lahko nadomesti ujemanje. Za to se uporablja funkcija regex_replace (). Tokrat pa je niz, kjer pride do zamenjave, nizni objekt, ne literal niza. Zato je treba knjižnico nizov vključiti v program. Ilustracija:

#vključi

#vključi

#vključi

z uporabo imenskega prostora std;

intglavni()
{
niz str= 'Evo, prihaja moj mož. Tam gre vaš mož. ';
niz newStr=regex_replace(str,regex('človek'), 'ženska');
stroški<<novoStr<<endl;

vrnitev 0;
}

Funkcija regex_replace (), kot je kodirana tukaj, nadomešča vsa ujemanja. Prvi argument funkcije je cilj, drugi je predmet regex, tretji pa nadomestni niz. Funkcija vrne nov niz, ki je cilj, vendar ima zamenjavo. Izhod je:

Prihaja moja ženska. Tam gre tvoja ženska.

Zaključek

Regularni izraz uporablja vzorce za ujemanje podnizov v nizu ciljnega zaporedja. Vzorci imajo metaznake. Pogosto uporabljene funkcije za regularne izraze C ++ so: regex_search (), regex_match () in regex_replace (). Regex je vzorec v dvojnih narekovajih. Vendar te funkcije vzamejo predmet regex kot argument in ne le regex. Regex mora biti narejen v predmet regex, preden ga lahko te funkcije uporabijo.