C ++

Grunnleggende om vanlig uttrykk i C ++

Grunnleggende om vanlig uttrykk i C ++
Tenk på følgende setning i sitater:

"Her er mannen min."

Denne strengen kan være inne i datamaskinen, og brukeren vil kanskje vite om den har ordet "mann". Hvis det har ordet mann, vil han kanskje endre ordet "mann" til "kvinne"; slik at strengen skal lyde:

"Her er kvinnen min."

Det er mange andre ønsker som disse fra datamaskinbrukeren; noen er komplekse. Regular Expression, forkortet, regex, er gjenstand for håndtering av disse problemene på datamaskinen. C ++ kommer med et bibliotek som heter regex. Så et C ++ - program for å håndtere regex bør begynne med:

#inkludere
#inkludere
bruker navneområde std;

Denne artikkelen forklarer grunnleggende om regulært uttrykk i C++.

Artikkelinnhold

  • Grunnleggende om vanlig uttrykk
  • Mønster
  • Karakterklasser
  • Matchende hvite rom
  • Perioden (.) i Mønsteret
  • Matchende repetisjoner
  • Matchende alternativ
  • Matchende begynnelse eller slutt
  • Gruppering
  • Icase og multiline regex_constants
  • Matcher hele målet
  • Match_results-objektet
  • Kampens posisjon
  • Søk og erstatt
  • Konklusjon

Grunnleggende om vanlig uttrykk

Regex

En streng som “Her er mannen min.”Over er målsekvensen eller målstrengen eller bare mål. "Mann", som det ble søkt etter, er det vanlige uttrykket, eller ganske enkelt, regex.

Matchende

Det sies at samsvar forekommer når ordet eller setningen det søkes etter er lokalisert. Etter samsvar kan en erstatning finne sted. For eksempel, etter at "mann" er plassert ovenfor, kan den erstattes med "kvinne".

Enkel matching

Det følgende programmet viser hvordan ordet "mann" matches.

#inkludere
#inkludere
bruker navneområde std;
int main ()

regex reg ("mann");
if (regex_search ("Her er mannen min.", reg))
cout << "matched" << endl;
ellers
cout << "not matched" << endl;
retur 0;

Funksjonen regex_search () returnerer true hvis det er samsvar og returnerer false hvis ingen samsvar forekommer. Her tar funksjonen to argumenter: den første er målstrengen, og den andre er regex-objektet. Selve regexet er "mann", i to anførselstegn. Den første setningen i hovedfunksjonen () danner regex-objektet. Regex er en type, og reg er regex-objektet. Programmets utgang er "matchet", da "mann" sees i målstrengen. Hvis "mann" ikke ble sett i målet, ville regex_search () returnert falsk, og utdataene ville ha blitt "ikke matchet".

Utdataene fra følgende kode er "ikke samsvarende":

regex reg ("mann");
if (regex_search ("Her er min fremstilling.", reg))
cout << "matched" << endl;
ellers
cout << "not matched" << endl;

Ikke samsvarende fordi regex "mannen" ikke ble funnet i hele målstrengen, "Her er min fremstilling."

Mønster

Det vanlige uttrykket, “mann” ovenfor, er veldig enkelt. Regexes er vanligvis ikke så enkle. Regulære uttrykk har metategn. Metategn er tegn med spesielle betydninger. En metakarakter er en karakter om tegn. C ++ regex-metategn er:

^ $ \ . * + ? () [] |

En regex, med eller uten metategn, er et mønster.

Karakterklasser

Firkantede braketter

Et mønster kan ha tegn innenfor firkantede parenteser. Med dette vil en bestemt posisjon i målstrengen matche noen av firkantene. Tenk på følgende mål:

"Katten er i rommet."
"Flaggermusen er i rommet."
"Rotten er i rommet."

Regex, [cbr] at ville matche katten i det første målet. Det ville matche flaggermus i det andre målet. Det ville matche rotte i det tredje målet. Dette er fordi "katt" eller "flaggermus" eller "rotte" begynner med 'c' eller 'b' eller 'r'. Følgende kodesegment illustrerer dette:

regex reg ("[cbr] at");
if (regex_search ("Katten er i rommet.", reg))
cout << "matched" << endl;
if (regex_search ("Flaggermusen er i rommet.", reg))
cout << "matched" << endl;
if (regex_search ("Rotten er i rommet.", reg))
cout << "matched" << endl;

Utgangen er:

matchet
matchet
matchet

Rekkevidde av tegn

Klassen, [cbr] i mønsteret [cbr], ville matche flere mulige tegn i målet. Det ville matche 'c' eller 'b' eller 'r' i målet. Hvis målet ikke har noe av 'c' eller 'b' eller 'r', etterfulgt av "at", vil det ikke være noen samsvar.

Noen muligheter som 'c' eller 'b' eller 'r' finnes i et område. Sifferområdet 0 til 9 har 10 muligheter, og mønsteret for det er [0-9]. Utvalget av små bokstaver, a til z, har 26 muligheter, og mønsteret for det er [a-z]. Utvalget av store bokstaver, A til Å, har 26 muligheter, og mønsteret for det er [AZ]. - er ikke offisielt et metakarakter, men innenfor firkantede parenteser, vil det indikere et område. Så, følgende produserer en kamp:

hvis (regex_search ("ID6id", regex ("[0-9]")))
cout << "matched" << endl;

Legg merke til hvordan regex er konstruert som det andre argumentet. Kampen skjer mellom sifferet, 6 i området, 0 til 9, og 6 i målet, "ID6id". Ovennevnte kode tilsvarer:

hvis (regex_search ("ID6id", regex ("[0123456789]")))
cout << "matched" << endl;

Følgende kode produserer en kamp:

char str [] = "ID6iE";
hvis (regex_search (str, regex ("[a-z]")))
cout << "matched" << endl;

Merk at det første argumentet her er en strengvariabel og ikke strengen bokstavelig. Kampen er mellom 'i' i [a-z] og 'i' i "ID6iE".

Ikke glem at en rekkevidde er en klasse. Det kan være tekst til høyre for området eller til venstre for området i mønsteret. Følgende kode produserer en kamp:

hvis (regex_search ("ID2id er en ID ", regex (" ID [0-9] id ")))
cout << "matched" << endl;

Kampen er mellom “ID [0-9] id” og “ID2id”. Resten av målstrengen, "er en ID," samsvares ikke i denne situasjonen.

Som brukt i regulære uttrykksemne (regexes), betyr ordklassen faktisk et sett. Det vil si at en av karakterene i settet skal matche.

Merk: Bindestreket - er en metategn bare innenfor firkantede parenteser, som indikerer et område. Det er ikke en metakarakteristikk i regex, utenfor firkantede parenteser.

Negasjon

En klasse med en rekkevidde kan negeres. Det vil si at ingen av tegnene i settet (klasse) skal stemme overens. Dette er indikert med ^ metategnet i begynnelsen av klassemønsteret, like etter den åpne firkantbraketten. Så, [^ 0-9] betyr å matche tegnet i riktig posisjon i målet, som ikke er noe tegn i området, inkludert 0 til 9. Så følgende kode gir ikke samsvar:

hvis (regex_search ("0123456789101112", regex ("[^ 0-9]")))
cout << "matched" << endl;
ellers
cout << "not matched" << endl;

Et siffer i området 0 til 9 kan bli funnet i hvilken som helst av målstrengposisjonene, "0123456789101112,"; så det er ingen samsvar - negasjon.

Følgende kode produserer en kamp:

hvis (regex_search ("ABCDEFGHIJ", regex ("[^ 0-9]")))
cout << "matched" << endl;

Ingen siffer ble funnet i målet, “ABCDEFGHIJ,”; så det er en kamp.

[a-z] er et område utenfor [^ a-z]. Og så er [^ a-z] negasjonen av [a-z].

[A-Z] er et område utenfor [^ A-Z]. Og så er [^ A-Z] negasjonen av [A-Z].

Andre negasjoner eksisterer.

Matchende hvite rom

"eller \ t eller \ r eller \ n eller \ f er et mellomromstegn. I den følgende koden samsvarer regex, “\ n” med '\ n' i målet:

hvis (regex_search ("Av linje en.\ r \ nFor linje to.", regex (" \ n ")))
cout << "matched" << endl;

Matcher alle hvite mellomromstegn

Mønsteret eller klassen som samsvarer med et hvitt mellomrom, er, [\ t \ r \ n \ f]. I følgende kode matches ":

hvis (regex_search ("en to", regex ("[\ t \ r \ n \ f]")))
cout << "matched" << endl;

Matcher alle tegn som ikke er mellomrom

Mønsteret eller klassen som samsvarer med alle tegn som ikke er mellomrom, er, [^ \ t \ r \ n \ f]. Følgende kode produserer et treff fordi det ikke er noe mellomrom i målet:

hvis (regex_search ("1234abcd", regex ("[^ \ t \ r \ n \ f]")))
cout << "matched" << endl;

Perioden (.) i Mønsteret

Perioden (.) i mønsteret samsvarer med alle tegn inkludert seg selv, unntatt \ n, i målet. En kamp produseres i følgende kode:

hvis (regex_search ("1234abcd", regex (".")))
cout << "matched" << endl;

Ingen samsvarende resultater i følgende kode fordi målet er “\ n”.

hvis (regex_search ("\ n", regex (".")))
cout << "matched" << endl;
ellers
cout << "not matched" << endl;

Merk: Inne i en karakterklasse med firkantede parenteser har perioden ingen spesiell betydning.

Matchende repetisjoner

Et tegn eller en gruppe tegn kan forekomme mer enn en gang i målstrengen. Et mønster kan matche denne repetisjonen. Metategnene, ?, *, + og brukes til å matche repetisjonen i målet. Hvis x er et tegn av interesse i målstrengen, har metategnene følgende betydning:

x *: betyr samsvar med 'x' 0 eller flere ganger, i.e., et hvilket som helst antall ganger
x +: betyr samsvar med 'x' 1 eller flere ganger, i.e., i hvert fall en gang
x? : betyr match 'x' 0 eller 1 gang
x n,: betyr samsvar med 'x' minst n eller flere ganger. Legg merke til kommaet.
x n: match 'x' nøyaktig n ganger
x n, m: match 'x' minst n ganger, men ikke mer enn m ganger.

Disse metategnene kalles kvantifiseringsmidler.

Illustrasjoner

*

* Samsvarer med forrige tegn eller foregående gruppe, null eller flere ganger. “O *” samsvarer med "o" i "hund" i målstrengen. Det samsvarer også med "oo" i "bok" og "ser". Regex, "o *" samsvarer med "boooo" i "The animal booooed.”. Merk: “o *” samsvarer med “grave”, der "o" forekommer null (eller mer) tid.

+

+ Samsvarer med forrige tegn eller forrige gruppe, 1 eller flere ganger. Kontrast med null eller flere ganger for *. Så regex, "e +" samsvarer med "e" i "eat", hvor "e" forekommer en gang. "E +" samsvarer også med "ee" i "sau", der "e" forekommer mer enn en gang. Merk: “e +” vil ikke matche “grave” fordi i "grave", "e" ikke forekommer minst en gang.

?

De ? samsvarer med forrige tegn eller forrige gruppe, 0 eller 1 gang (og ikke mer). Så, "e?”Samsvarer med“ grave ”fordi 'e' forekommer i" grave ", null tid. “E?”Samsvarer med“ sett ”fordi 'e' forekommer i" sett ", en gang. Merk: “e?”Samsvarer fremdeles med“ sau ”; selv om det er to e-er i "sauer". Det er en nyanse her - se senere.

n,

Dette samsvarer med minst n påfølgende repetisjoner av et forrige tegn eller en foregående gruppe. Så regex, "e 2," samsvarer med de to 'eene i målet, "sau", og de tre' eene i målet "sheeep". "E 2," samsvarer ikke med "sett", fordi "sett" bare har en "e".

n

Dette samsvarer med nøyaktig n påfølgende repetisjon av et foregående tegn eller en gruppe som gikk foran. Så regex, "e 2" samsvarer med de to e-ene i målet, "sau". "E 2" samsvarer ikke med "sett" fordi "sett" bare har en "e". Vel, "e 2" samsvarer med to 'eer i målet, "sheeep". Det er en nyanse her - se senere.

n, m

Dette samsvarer med flere påfølgende repetisjoner av et foregående tegn eller en foregående gruppe, hvor som helst fra n til m, inkludert. Så "e 1,3" samsvarer ikke med noe i "dig", som ikke har "e". Den samsvarer med den ene 'e' i "sett", de to 'e er i "sauer", de tre' e er i "sheeep", og tre 'e er i "sheeeep". Det er en nyanse i den siste kampen - se senere.

Matchende alternativ

Vurder følgende målstreng på datamaskinen.

“Gården har svin i forskjellige størrelser.”

Programmereren vil kanskje vite om dette målet har "geit" eller "kanin" eller "gris". Koden vil være som følger:

char str [] = "Gården har svin i forskjellige størrelser.";
hvis (regex_search (str, regex ("geit | kanin | gris")))
cout << "matched" << endl;
ellers
cout << "not matched" << endl;

Koden gir en kamp. Legg merke til bruken av alternativtegnet,. Det kan være to, tre, fire og flere alternativer. C ++ vil først prøve å matche det første alternativet, "geit", ved hver karakterposisjon i målstrengen. Hvis det ikke lykkes med "geit", prøver det neste alternativ, "kanin". Hvis det ikke lykkes med "kanin", prøver det neste alternativ, "gris". Hvis “gris” mislykkes, fortsetter C ++ til neste posisjon i målet og starter med det første alternativet igjen.

I ovennevnte kode matches "gris".

Matchende begynnelse eller slutt

Begynnelse


Hvis ^ er i begynnelsen av regexen, kan startteksten til målstrengen matches med regexen. I den følgende koden er starten på målet “abc”, som matches:

hvis (regex_search ("abc og def", regex ("^ abc")))
cout << "matched" << endl;

Ingen samsvar finner sted i følgende kode:

hvis (regex_search ("Ja, abc og def", regex ("^ abc")))
cout << "matched" << endl;
ellers
cout << "not matched" << endl;

Her er ikke “abc” i begynnelsen av målet.

Merk: Circflex-tegnet, '^', er en metategn ved starten av regex, som samsvarer med starten på målstrengen. Det er fortsatt et metakarakter i begynnelsen av karakterklassen, der det negerer klassen.

Slutt

Hvis $ er på slutten av regexen, kan sluttteksten til målstrengen matches med regex. I den følgende koden er slutten av målet “xyz”, som matches:

hvis (regex_search ("uvw og xyz", regex ("xyz $")))
cout << "matched" << endl;

Ingen samsvar finner sted i følgende kode:

hvis (regex_search ("uvw og xyz final", regex ("xyz $")))
cout << "matched" << endl;
ellers
cout << "not matched" << endl;

Her er ikke "xyz" på slutten av målet.

Gruppering

Parenteser kan brukes til å gruppere tegn i et mønster. Vurder følgende regeks:

"en konsert (pianist)"

Gruppen her er “pianist” omgitt av metategnene (og). Det er faktisk en undergruppe, mens "en konsert (pianist)" er hele gruppen. Vurder følgende:

"(Pianisten er god)"

Her er undergruppen eller understrengen "pianisten er god".

Understrenger med felles deler

En bokholder er en person som tar seg av bøker. Se for deg et bibliotek med bokholder og bokhylle. Anta at en av følgende målstrenger er i datamaskinen:

"Biblioteket har en bokhylle som er beundret.";
"Her er bokholderen.";
"Bokholderen jobber med bokhyllen.";

Anta at programmererens interesse ikke er å vite hvilken av disse setningene som ligger i datamaskinen. Likevel er hans interesse å vite om "bokhylle" eller "bokholder" er til stede i hvilken målstreng som helst i datamaskinen. I dette tilfellet kan regexen hans være:

"bokhylle | bokholder."

Bruke veksling.

Legg merke til at "bok", som er felles for begge ordene, har blitt skrevet to ganger, i de to ordene i mønsteret. For å unngå å skrive "bok" to ganger, vil regexen være bedre skrevet som:

"bok (hylle | keeper)"

Her har gruppen, "hylle | keeper" Alternativmetakarakteren fortsatt blitt brukt, men ikke i to lange ord. Det har blitt brukt til de to sluttdelene av de to lange ordene. C ++ behandler en gruppe som en enhet. Så, C ++ vil se etter "hylle" eller "keeper" som kommer umiddelbart etter "bok". Utdataene fra følgende kode er "matchet":

char str [] = "Biblioteket har en bokhylle som er beundret.";
hvis (regex_search (str, regex ("bok (hylle | keeper)")))
cout << "matched" << endl;

"Bokhylle" og ikke "bokholder" har blitt matchet.

Icase og multiline regex_constants

icase

Matching er store og små bokstaver som standard. Imidlertid kan det gjøres skiftesensitivt. For å oppnå dette, bruk regex :: icase-konstanten, som i følgende kode:

hvis (regex_search ("Feedback", regex ("feed", regex :: icase)))
cout << "matched" << endl;

Utgangen er "matchet". Så "Tilbakemelding" med store bokstaver "F" har blitt matchet av "feed" med små bokstaver "f". “Regex :: icase” har blitt gjort til det andre argumentet til regex () -konstruktøren. Uten det ville uttalelsen ikke gi noen kamp.

Multiline

Vurder følgende kode:

char str [] = "linje 1 \ nline 2 \ nline 3";
hvis (regex_search (str, regex ("^.* $ ")))
cout << "matched" << endl;
ellers
cout << "not matched" << endl;

Utgangen er "ikke matchet". Regex, “^.* $, ”Samsvarer med målstrengen fra begynnelsen til slutten. “.* ”Betyr hvilket som helst tegn unntatt \ n, null eller flere ganger. Så på grunn av de nye linjetegnene (\ n) i målet, var det ingen samsvar.

Målet er en streng med flere linjer. For at '.'for å matche den nye linjekarakteren, må den konstante "regex :: multiline" gjøres, det andre argumentet for regex () -konstruksjonen. Følgende kode illustrerer dette:

char str [] = "linje 1 \ nline 2 \ nline 3";
hvis (regex_search (str, regex ("^.* $ ", regex :: multiline)))
cout << "matched" << endl;
ellers
cout << "not matched" << endl;

Matcher hele målstrengen

For å matche hele målstrengen, som ikke har det nye linjetegnet (\ n), kan funksjonen regex_match () brukes. Denne funksjonen er forskjellig fra regex_search (). Følgende kode illustrerer dette:

char str [] = "første andre tredjedel";
hvis (regex_match (str, regex (".*sekund.* ")))
cout << "matched" << endl;

Det er en kamp her. Vær imidlertid oppmerksom på at regex samsvarer med hele målstrengen, og målstrengen har ingen '\ n'.

Match_results-objektet

Regex_search () -funksjonen kan ta et argument mellom målet og regex-objektet. Dette argumentet er match_results-objektet. Hele matchede (del) streng og delstrenger som er matchet kan være kjent med den. Dette objektet er en spesiell matrise med metoder. Objekttypen match_results er cmatch (for strenglitteraler).

Å skaffe kamper

Vurder følgende kode:

char str [] = "Kvinnen du lette etter!";
cmatch m;
hvis (regex_search (str, m, regex ("w.m.n ")))
cout << m[0] << endl;

Målstrengen har ordet "kvinne". Produksjonen er "kvinne", som tilsvarer regex, "w.m.n ”. Ved indeks null har den spesielle matrisen den eneste kampen, som er "kvinne".

Med klassealternativer sendes bare den første understrengen som finnes i målet, til den spesielle matrisen. Følgende kode illustrerer dette:

cmatch m;
if (regex_search ("Rotten, katten, flaggermusen)!", m, regex (" [bcr] at ")))
cout << m[0] << endl;
cout << m[1] << endl;
cout << m[2] << endl;

Resultatet er "rotte" fra indeks null. m [1] og m [2] er tomme.

Med alternativer sendes bare den første understrengen som finnes i målet, til den spesielle matrisen. Følgende kode illustrerer dette:

if (regex_search ("Kaninen, geiten, grisen!", m, regex (" geit | kanin | gris ")))
cout << m[0] << endl;
cout << m[1] << endl;
cout << m[2] << endl;

Resultatet er "kanin" fra indeks null. m [1] og m [2] er tomme.

Grupperinger

Når grupper er involvert, går det komplette mønsteret i celle null i den spesielle matrisen. Den neste understrengen som blir funnet, går inn i celle 1; understrengen som følger, går inn i celle 2; og så videre. Følgende kode illustrerer dette:

if (regex_search ("Beste bokhandler i dag!", m, regex (" book ((sel) (ler)) ")))
cout << m[0] << endl;
cout << m[1] << endl;
cout << m[2] << endl;
cout << m[3] << endl;

Utgangen er:

bokhandler
selger
sel
ler

Merk at gruppen (selgeren) kommer før gruppen (sel).

Kampens posisjon

Posisjonen for samsvar for hver understreng i cmatch-matrisen kan være kjent. Telling begynner fra første tegn i målstrengen, på posisjon null. Følgende kode illustrerer dette:

cmatch m;
if (regex_search ("Beste bokhandler i dag!", m, regex (" 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;

Legg merke til bruken av posisjonsegenskapen, med celleindeksen, som et argument. Utgangen er:

bokhandler-> 5
selger-> 9
sel-> 9
ler-> 12

Søk og erstatt

Et nytt ord eller uttrykk kan erstatte kampen. Regex_replace () -funksjonen brukes til dette. Denne gangen er strengen der erstatningen skjer imidlertid strengobjektet, ikke strengen bokstavelig. Så strengbiblioteket må inkluderes i programmet. Illustrasjon:

#inkludere
#inkludere
#inkludere
bruker navneområde std;
int main ()

string str = "Her kommer mannen min. Der går mannen din.";
streng newStr = regex_replace (str, regex ("mann"), "kvinne");
cout << newStr << endl;
retur 0;

Regex_replace () -funksjonen, som kodet her, erstatter alle kampene. Det første argumentet til funksjonen er målet, det andre er regex-objektet, og det tredje er erstatningsstrengen. Funksjonen returnerer en ny streng, som er målet, men som erstatningen. Utgangen er:

“Her kommer kvinnen min. Der går kvinnen din.”

Konklusjon

Regulært uttrykk bruker mønstre for å matche understrenger i målsekvensstrengen. Mønstre har metategn. Vanlige funksjoner for C ++ regulære uttrykk er: regex_search (), regex_match () og regex_replace (). En regex er et mønster i dobbelt anførselstegn. Imidlertid tar disse funksjonene regex-objektet som et argument og ikke bare regex. Regex må gjøres til et regex-objekt før disse funksjonene kan bruke det.

Hvordan bruke AutoKey til å automatisere Linux-spill
AutoKey er et desktopautomatiseringsverktøy for Linux og X11, programmert i Python 3, GTK og Qt. Ved å bruke skript og MACRO-funksjonalitet kan du aut...
Hvordan vise FPS-teller i Linux-spill
Linux-spill fikk et stort press da Valve kunngjorde Linux-støtte for Steam-klient og spillene deres i 2012. Siden den gang har mange AAA- og indiespil...
Hvordan laste ned og spille Sid Meier's Civilization VI på Linux
Introduksjon til spillet Civilization 6 er et moderne syn på det klassiske konseptet som ble introdusert i serien av Age of Empires-spillene. Ideen va...