Ta niz je morda v računalniku in uporabnik bo morda želel vedeti, ali ima besedo "človek". Če ima besedo moški, bo morda želel besedo "moški" spremeniti v "ženska"; tako da naj se niz glasi:
"Tu je moja ženska."Takšnih želja uporabnika računalnika je še veliko; nekateri so zapleteni. Redni izraz, okrajšan, regularni izraz, je predmet obravnavanja teh težav v računalniku. C ++ ima knjižnico z imenom regex. Torej, program C ++ za obdelavo regularnih izrazov se mora začeti z:
#include#include
uporaba imenskega prostora std;
Ta članek razlaga osnove regularnega izražanja v jeziku C++.
Vsebina članka
- Osnove rednega izražanja
- Vzorec
- Razredi znakov
- Ujemanje presledkov
- Obdobje (.) v vzorcu
- Ujemanje ponovitev
- Ujemajoča se alternacija
- Ujemanje začetka ali konca
- Združevanje v skupine
- Stavki icase in več vrstic regex_constants
- Ujemanje celotnega cilja
- Predmet match_results
- Položaj tekme
- Poiščite in zamenjajte
- Zaključek
Osnove rednega izražanja
Regex
Niz, kot je »Tu je moj človek.”Zgoraj je ciljno zaporedje ali ciljni niz ali preprosto cilj. "Moški", ki je bil iskan, je regularni izraz ali preprosto regex.
Ujemanje
Do ujemanja naj bi prišlo, ko se najde beseda ali besedna zveza, ki jo iščete. Po ujemanju lahko pride do zamenjave. Na primer, ko je »moški« nameščen zgoraj, ga lahko nadomesti z »ženska«.
Preprosto ujemanje
Naslednji program prikazuje, kako se ujema beseda "človek".
#include#include
uporaba imenskega prostora std;
int main ()
regularni izraz reg ("človek");
if (regex_search ("Tukaj je moj človek.", reg))
cout << "matched" << endl;
drugače
cout << "not matched" << endl;
vrnitev 0;
Funkcija regex_search () vrne true, če obstaja ujemanje, in vrne false, če ne pride do ujemanja. Tu ima funkcija dva argumenta: prvi je ciljni niz, drugi pa objekt regularnega izraza. Regex sam je "človek", z dvojnimi narekovaji. Prvi stavek v funkciji main () tvori objekt regularnega izraza. Redovni izraz je vrsta, reg pa objekt regularnega izraza. Izhodni podatki zgornjega programa se "ujemajo", saj je v ciljnem nizu viden "man". Če v cilju ni bilo videti "man", bi regex_search () vrnil false in izhod ne bi bil "ujemajoč".
Rezultat naslednje kode se "ne ujema":
regularni izraz reg ("človek");if (regex_search ("Tukaj je moja izdelava.", reg))
cout << "matched" << endl;
drugače
cout << "not matched" << endl;
Ni se ujemalo, ker regularnega izraza "man" ni bilo mogoče najti v celotnem ciljnem nizu, "Tukaj je moja izdelava."
Vzorec
Regularni izraz "človek" zgoraj je zelo preprost. Regeksi običajno niso tako preprosti. Regularni izrazi imajo metaznake. Metaznaki so znaki s posebnim pomenom. Metaznak je znak o znakih. Metaznaki regularnih izrazov C ++ so:
^ $ \ . * + ? () [] |Redovni izraz z metaznaki ali brez njih je vzorec.
Razredi znakov
Kvadratni oklepaji
Vzorec ima lahko znake v oglatih oklepajih. S tem bi se določen položaj v ciljnem nizu ujemal s katerim koli znakom v oglatih oklepajih. Upoštevajte naslednje cilje:
"Mačka je v sobi.""Netopir je v sobi."
"Podgana je v sobi."
Redovni izraz, [cbr] at bi se ujemal z mačko v prvi tarči. V drugi tarči bi se ujemal z netopirjem. V tretji tarči bi se ujemal s podgano. To je zato, ker se "mačka" ali "netopir" ali "podgana" začne s "c" ali "b" ali "r". To ponazarja naslednji segment kode:
regularni izraz reg ("[cbr] at");if (regex_search ("Mačka je v sobi.", reg))
cout << "matched" << endl;
if (regex_search ("Netopir je v sobi.", reg))
cout << "matched" << endl;
if (regex_search ("Podgana je v sobi.", reg))
cout << "matched" << endl;
Rezultat je:
ujemajoujemajo
ujemajo
Razpon znakov
Razred, [cbr] v vzorcu [cbr], bi se ujemal z več možnimi znaki v cilju. V tarči bi se ujemal s 'c' ali 'b' ali 'r'. Če cilj nima nobenega od 'c' ali 'b' ali 'r', čemur sledi »at«, ne bi bilo ujemanja.
Nekatere možnosti, kot so 'c' ali 'b' ali 'r', obstajajo v območju. Razpon števk od 0 do 9 ima 10 možnosti in vzorec za to je [0-9]. Obseg malih abeced, od a do z, ima 26 možnosti, vzorec za to pa je [a-z]. Razpon velikih črk, od A do Ž, ima 26 možnosti, vzorec za to pa je [A-Z]. - ni uradno metaznak, vendar bi v oglatih oklepajih označeval obseg. Torej, naslednje ustvari ujemanje:
if (iskanje regularnih izrazov ("ID6id", regularni izraz ("[0-9]")))cout << "matched" << endl;
Upoštevajte, kako je bil regularni izraz sestavljen kot drugi argument. Do ujemanja pride med števko, 6 v območju, od 0 do 9, in 6 v tarči, "ID6id". Zgornja koda je enakovredna:
if (iskanje regularnih izrazov ("ID6id", regularni izraz ("[0123456789]")))cout << "matched" << endl;
Naslednja koda ustvari ujemanje:
char str [] = "ID6iE";if (iskanje regularnih izrazov (str, regularni izraz ("[a-z]")))
cout << "matched" << endl;
Upoštevajte, da je tukaj prvi argument spremenljivka niza in ne niz literala. 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:
if (regex_search ("ID2id je ID ", regularni izraz (" ID [0-9] id ")))cout << "matched" << endl;
Ujemanje je med “ID [0-9] id” in “ID2id”. Preostali ciljni niz, »je ID«, se v tej situaciji ne ujema.
Kot uporabljen v temi regularnega izraza (regularni izrazi), beseda razred dejansko pomeni niz. To pomeni, da se mora eden od znakov v nizu ujemati.
Opomba: vezaj - je metaznak samo v oglatih oklepajih, ki označuje obseg. To ni metaznak v regularnem izrazu, zunaj oglatih oklepajev.
Negacija
Razred, ki vključuje obseg, je mogoče zanikati. To pomeni, da se ne smejo ujemati nobeni znaki v naboru (razredu). To je označeno z znakom ^ na začetku vzorca razreda, takoj za začetnim oklepajem. Torej, [^ 0-9] pomeni ujemanje znaka na ustreznem mestu v cilju, kar ni noben znak v obsegu, vključno z 0 do 9. Torej naslednja koda ne bo dala ujemanja:
if (iskanje regularnih izrazov ("0123456789101112", regularni izraz ("[^ 0-9]")))cout << "matched" << endl;
drugače
cout << "not matched" << endl;
Številko v območju od 0 do 9 lahko najdemo v katerem koli od ciljnih položajev niza, "0123456789101112,"; torej ni ujemanja - negacije.
Naslednja koda ustvari ujemanje:
če (iskanje regularnih izrazov ("ABCDEFGHIJ", regularni izraz ("[^ 0-9]")))cout << "matched" << endl;
V cilju "ABCDEFGHIJ" ni bilo mogoče najti nobene številke; torej obstaja tekma.
[a-z] je obseg zunaj [^ a-z]. In tako je [^ a-z] negacija [a-z].
[A-Z] je obseg zunaj [^ A-Z]. In tako [^ A-Z] je negacija [A-Z].
Obstajajo tudi druge negacije.
Ujemanje presledkov
"ali \ t ali \ r ali \ n ali \ f je presledek. V naslednji kodi se regularni izraz "\ n" ujema z '\ n' v cilju:
if (regex_search ("Prve vrstice.\ r \ nDruge vrstice.", regularni izraz (" \ n ")))cout << "matched" << endl;
Ujemanje katerega koli presledka
Vzorec ali razred, ki se ujema s katerim koli presledkom, je [\ t \ r \ n \ f]. V naslednji kodi se ujema:
if (iskanje regularnih izrazov ("ena dva", regularni izraz ("[\ t \ r \ n \ f]")))cout << "matched" << endl;
Ujemanje katerega koli znaka, ki ni presledek
Vzorec ali razred, ki se ujema s katerim koli nebelim presledkom, je [^ \ t \ r \ n \ f]. Naslednja koda ustvari ujemanje, ker v cilju ni presledkov:
if (iskanje regularnih izrazov ("1234abcd", regularni izraz ("[^ \ t \ r \ n \ f]")))cout << "matched" << endl;
Obdobje (.) v vzorcu
Obdobje (.) v vzorcu se ujema s katerim koli znakom, vključno s samim, razen \ n, v cilju. Ujema se v naslednji kodi:
if (regex_search ("1234abcd", regex (".")))cout << "matched" << endl;
V naslednji kodi ni ustreznih rezultatov, ker je cilj "\ n".
if (iskanje regularnega izraza ("\ n", izraz regularnega izraza (".")))cout << "matched" << endl;
drugače
cout << "not matched" << endl;
Opomba: Tačka nima posebnega pomena v razredu znakov v oglatih oklepajih.
Ujemanje ponovitev
Znak ali skupina znakov se lahko v ciljnem nizu pojavi večkrat. Vzorec se lahko ujema s to ponovitvijo. Metaznaki, ?, *, + in se uporabljajo za ujemanje s ponovitvijo v cilju. Če je x znak, ki nas zanima v ciljnem nizu, imajo metaznaki naslednji pomen:
x *: pomeni ujemanje 'x' 0 ali več krat, tj.e., poljubno število kratx +: pomeni ujemanje 'x' 1 ali večkrat, tj.e., vsaj enkrat
x? : pomeni ujemanje 'x' 0 ali 1-krat
x n,: pomeni, da se vsaj x ali večkrat ujema z 'x'. Upoštevajte vejico.
x n: natančno n krat se ujema z 'x'
x n, m: ujema se z 'x' vsaj n-krat, vendar ne več kot m-krat.
Ti metaznaki se imenujejo količniki.
Ilustracije
*
Znak * se nič ali večkrat ujema s predhodnim znakom ali prejšnjo skupino. “O *” se ujema z “o” v “dog” ciljnega niza. Prav tako se ujema z "oo" v "book" in "looking". Redovni izraz "o *" se ujema z "boooo" v "Žival booooed.". Opomba: “o *” se ujema z “dig”, kjer se za “o” pojavi nič (ali več) čas.
+
Znak + se 1 ali večkrat ujema s prejšnjim znakom ali prejšnjo skupino. Kontrastirajte z nič ali večkrat za *. Torej se regularni izraz "e +" ujema z "e" v "jesti", kjer se "e" pojavi enkrat. "E +" se ujema tudi z "ee" v "ovaca", kjer se "e" pojavlja večkrat. Opomba: "e +" se ne bo ujemalo 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, »npr?"Se ujema z" dig ", ker se" e "pojavlja v" dig ", nič časa. „E?”Se ujema z“ set ”, ker se e enkrat pojavi v“ set ”. Opomba: „e?"Še vedno ustreza" ovca "; čeprav sta dva "e" v "ovcah". Tu je odtenek - glej kasneje.
n,
Ta se ujema z vsaj n zaporednimi ponovitvami predhodnega znaka ali predhodne skupine. Torej se regularni izraz "e 2," ujema z dvema "e" v cilju, "ovca" in tremi "e" v ciljni "ovci". "E 2," se ne ujema z "set", ker ima "set" samo eno "e".
n
To se ujema z natančno n zaporednimi ponovitvami prejšnjega znaka ali predhodne skupine. Torej se regularni izraz "e 2" ujema z dvema "e" v cilju, "ovaca". "E 2" se ne ujema z "set", ker ima "set" samo eno "e". No, "e 2" se ujema z dvema e v tarči, "ovca". Tu je odtenek - glej kasneje.
n, m
Ta se ujema z več zaporednimi ponovitvami predhodnega znaka ali predhodne skupine, kjer koli od n do vključno m. Torej, "e 1,3" se v "dig" ne ujema z nič, kar nima "e". Ujema se z enim 'e' v 'set', dve 'e' v 'ovaca', tri 'e' v 'sheeep' in tri 'e' in 'sheeeep'. Na zadnji tekmi je odtenek - glej kasneje.
Ujemanje alternacij
Razmislite o naslednjem ciljnem nizu v računalniku.
»Na kmetiji so prašiči različnih velikosti."
Programer bi morda želel vedeti, ali ima ta tarča "kozo", "zajca" ali "prašiča". Koda bi bila naslednja:
char str [] = "Na kmetiji so prašiči različnih velikosti.";if (iskanje regularnih izrazov (str, regularni izraz ("koza | zajec | prašič))))
cout << "matched" << endl;
drugače
cout << "not matched" << endl;
Koda ustvari ujemanje. Upoštevajte uporabo znaka izmene, |. Možnosti so lahko dve, tri, štiri in več. C ++ bo najprej poskušal najti prvo alternativo, "kozo", na vsakem položaju znaka v ciljnem nizu. Če s "kozo" ne uspe, poskusi z naslednjo alternativo, "zajec". Če z "zajcem" ne uspe, poskusi z naslednjo alternativo, "prašič". Če »prašič« ne uspe, se C ++ premakne na naslednji položaj v cilju in znova začne s prvo alternativo.
V zgornji kodi se ujema »prašič«.
Ujemanje začetka ali konca
Začetek
Če je ^ na začetku regularnega izraza, se lahko z začetnim besedilom ciljnega niza ujema z regularnim izrazom. V naslednji kodi je začetek cilja "abc", ki se ujema:
cout << "matched" << endl;
V naslednji kodi ni ujemanja:
if (iskanje regularnih izrazov ("Da, abc in def", regularni izraz ("^ abc")))cout << "matched" << endl;
drugače
cout << "not matched" << endl;
Tu "abc" ni na začetku cilja.
Opomba: Znak cirkumfleksa, '^', je metaznak na začetku regularnega izraza, ki se ujema z začetkom ciljnega niza. Še vedno je metaznak na začetku razreda znakov, kjer negira razred.
Konec
Če je $ na koncu regularnega izraza, lahko regularni izraz ujema s končnim besedilom ciljnega niza. V naslednji kodi je konec cilja »xyz«, ki se ujema:
if (iskanje regularnih izrazov ("uvw in xyz", regularni izraz ("xyz $")))cout << "matched" << endl;
V naslednji kodi ni ujemanja:
if (iskanje regularnih izrazov ("uvw in xyz final", regularni izraz ("xyz $")))cout << "matched" << endl;
drugače
cout << "not matched" << endl;
Tu "xyz" ni na koncu cilja.
Združevanje v skupine
V oklepajih lahko združimo znake v vzorec. Razmislite o naslednjem regularnem izrazu:
"koncert (pianist)"Skupina tukaj je "pianistka", obdana z metaznaki (in). Pravzaprav gre za podskupino, medtem ko je "koncert (pianist)" celotna skupina. Upoštevajte naslednje:
"(Pianist je dober)"Tu je podskupina ali podniz »pianist dober«.
Podnizi s skupnimi 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čudujejo.";"Tu je knjigovodja.";
"Knjigovodja dela s knjižno polico.";
Predpostavimo, da programerja ne zanima, 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 lahko njegov regularni izraz:
"knjižna polica | knjigovodja."Uporaba izmeničnega toka.
Opazite, da je bila "knjiga", ki je skupna obema besedama, vtipkani dvakrat, in sicer v obe besedi v vzorcu. Da bi se izognili dvakratnemu tipkanju »book«, bi bil regularni izraz bolje napisati kot:
"knjiga (polica | imetnik)"Tukaj je skupina, "polic | čuvaj". Metaznak izmenjave je še vedno uporabljen, vendar ne za dve dolgi besedi. Uporabljen je bil za dva končna dela dveh dolgih besed. C ++ obravnava skupino kot entiteto. Torej, C ++ bo poiskal "polico" ali "imetnika", ki pride takoj za "knjigo". Rezultat naslednje kode se "ujema":
char str [] = "Knjižnica ima knjižno polico, ki jo občudujejo.";if (regex_search (str, regex ("knjiga (polica | skrbnik)")))
cout << "matched" << endl;
„Knjižna polica“ in ne „knjigovodja“ sta bila ujeta.
Stavki icase in več vrstic regex_constants
icase
Ujemanje privzeto razlikuje med velikimi in malimi črkami. Vendar pa lahko postane neobčutljiv na velike in male črke. Da bi to dosegli, uporabite konstanto regex :: icase, kot v naslednji kodi:
if (regex_search ("Feedback", regex ("feed", regex :: icase)))cout << "matched" << endl;
Izhod je "usklajen". Torej, »Feedback« z velikimi črkami »F« se ujema z »feed« z malimi črkami »f«. “Regex :: icase” je bil drugi argument konstruktorja regex (). Brez tega izjava ne bi povzročila ujemanja.
Multiline
Upoštevajte naslednjo kodo:
char str [] = "vrstica 1 \ n vrstica 2 \ n vrstica 3";if (regex_search (str, regex ("^.* $ ")))
cout << "matched" << endl;
drugače
cout << "not matched" << endl;
Izhod je "ni enak". Redovni izraz "^.* $, «Se ujema s ciljnim nizom od začetka do konca. “.* ”Pomeni kateri koli znak, razen \ n, nič ali večkrat. Torej, zaradi znakov za novo vrstico (\ n) v cilju ni bilo nobenega ujemanja.
Cilj je večvrstični niz. Da bi.', da se ujema z znakom nove vrstice, je treba narediti konstanto "regex :: multiline", drugi argument konstrukcije regex (). Naslednja koda to ponazarja:
char str [] = "vrstica 1 \ n vrstica 2 \ n vrstica 3";if (regex_search (str, regex ("^.* $ ", regularni izraz: večvrstični))))
cout << "matched" << endl;
drugače
cout << "not matched" << endl;
Ujemanje celotnega ciljnega niza
Za ujemanje s celotnim ciljnim nizom, ki nima znaka nove vrstice (\ n), lahko uporabimo funkcijo regex_match (). Ta funkcija se razlikuje od regex_search (). Naslednja koda to ponazarja:
char str [] = "prva druga tretjina";if (regex_match (str, regex (".* drugo.* ")))
cout << "matched" << endl;
Tu je tekma. Vendar upoštevajte, da se regularni izraz ujema s celotnim ciljnim nizom in ciljni niz nima nobenega \ \ n.
Predmet match_results
Funkcija regex_search () lahko sprejme argument med ciljem in objektom regularnega izraza. Ta argument je objekt match_results. Z njim lahko poznamo celoten usklajeni niz (del) in ujemajoče se nize. Ta objekt je posebna matrika z metodami. Tip predmeta match_results je cmatch (za nizovne literale).
Pridobivanje tekem
Upoštevajte naslednjo kodo:
char str [] = "Ženska, ki ste jo iskali!";primerjava m;
if (regex_search (str, m, regex ("w.m.n ")))
cout << m[0] << endl;
Ciljni niz ima besedo "ženska". Rezultat je „ženska“, kar ustreza regularnemu izrazu, „w.m.n ". Pri indeksu nič ima posebna matrika edino ujemanje, in sicer "ženska".
Pri možnostih razreda se v posebno matriko pošlje samo prvi podniz, ki ga najdemo v cilju. Naslednja koda to ponazarja:
primerjava m;if (regex_search ("Podgana, mačka, netopir!", m, regularni izraz (" [bcr] at ")))
cout << m[0] << endl;
cout << m[1] << endl;
cout << m[2] << endl;
Rezultat je "podgana" iz indeksa nič. m [1] in m [2] sta prazni.
Pri drugih možnostih se v posebno polje pošlje samo prvi podniz, ki ga najdemo v cilju. Naslednja koda to ponazarja:
if (regex_search ("zajec, koza, prašič!", m, regularni izraz (" koza | zajec | prašič ")))cout << m[0] << endl;
cout << m[1] << endl;
cout << m[2] << endl;
Rezultat je "zajec" iz indeksa nič. m [1] in m [2] sta prazni.
Skupine
Ko so vključene skupine, se celoten vzorec, ki se ujema, premakne v nič celico posebnega polja. Naslednji najdeni podniz gre v celico 1; podniz, ki sledi, gre v celico 2; in tako naprej. Naslednja koda to ponazarja:
if (regex_search ("Najboljša knjigarna danes!", m, regularni izraz (" book ((sel) (ler)) ")))cout << m[0] << endl;
cout << m[1] << endl;
cout << m[2] << endl;
cout << m[3] << endl;
Rezultat je:
prodajalec knjigprodajalec
sel
ler
Upoštevajte, da skupina (prodajalec) pride pred skupino (sel).
Položaj tekme
Položaj ujemanja za vsak podniz v matrični matriki je lahko znan. Štetje se začne od prvega znaka ciljnega niza, na položaju nič. Naslednja koda to ponazarja:
primerjava m;if (regex_search ("Najboljša knjigarna danes!", m, regularni izraz (" book ((sel) (ler)) ")))
cout << m[0] << "->" << m.position(0) << endl;
cout << m[1] << "->" << m.position(1) << endl;
cout << m[2] << "->" << m.position(2) << endl;
cout << m[3] << "->" << m.position(3) << endl;
Kot argument upoštevajte uporabo lastnosti položaja z indeksom celice. Rezultat je:
prodajalec knjig-> 5prodajalec-> 9
sel-> 9
ler-> 12
Poiščite in zamenjajte
Ujemanje lahko nadomesti nova beseda ali besedna zveza. Za to se uporablja funkcija regex_replace (). Vendar je tokrat niz, pri katerem pride do zamenjave, nizni objekt in ne literal niza. Torej, knjižnica nizov mora biti vključena v program. Ilustracija:
#include#include
#include
uporaba imenskega prostora std;
int main ()
string str = "Tukaj prihaja moj mož. Gre tvoj mož.";
string newStr = regex_replace (str, regex ("moški"), "ženska");
cout << newStr << endl;
vrnitev 0;
Funkcija regex_replace (), kot je tu kodirana, nadomešča vsa ujemanja. Prvi argument funkcije je cilj, drugi je objekt regularnega izraza in tretji nadomestni niz. Funkcija vrne nov niz, ki je ciljni, vendar nadomestni. Rezultat je:
»Prihaja moja ženska. Tu gre tvoja ženska."
Zaključek
Regularni izraz uporablja vzorce za ujemanje podnizov v ciljnem nizu zaporedja. Vzorci imajo metaznake. Pogosto uporabljene funkcije za regularne izraze C ++ so: regex_search (), regex_match () in regex_replace (). Redovni izraz je vzorec v dvojnih narekovajih. Vendar te funkcije argumentirajo objekt regularnega izraza in ne samo regularnega izraza. Redovni izraz je treba narediti v objekt regularnega izraza, preden ga te funkcije lahko uporabijo.