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, kan han kanskje endre ordet "mann" til "kvinne"; slik at strengen skal lese:

"Her er kvinnen min.""

Det er mange andre ønsker som disse fra datamaskinbrukeren; Noen er sammensatte. Regelmessig uttrykk, forkortet, regex, er gjenstand for å håndtere disse problemene av datamaskinen. C ++ kommer med et bibliotek som heter regex. Så et C ++ -program for å håndtere regex bør begynne med:

#inkludere
#inkludere
ved hjelp av navneområdet STD;

Denne artikkelen forklarer grunnleggende uttrykk for vanlige uttrykk i C++.

Artikkelinnhold

  • Regelmessige uttrykk for grunnleggende
  • Mønster
  • Karakterklasser
  • Matchende hvitespaser
  • Perioden (.) i mønsteret
  • Matchende repetisjoner
  • Matchende veksling
  • Matchende begynnelse eller slutt
  • Gruppering
  • Icase og multiline regex_constants
  • Matcher hele målet
  • Match_results -objektet
  • Matchposisjon
  • Søk og erstatt
  • Konklusjon

Regelmessige uttrykk for grunnleggende

Regex

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

Matchende

Matching sies å oppstå når ordet eller setningen som blir søkt etter ligger. Etter matching kan en erstatning finne sted. Etter at "mann" er lokalisert ovenfor, kan den erstattes av "kvinne".

Enkel matching

Følgende program viser hvordan ordet “mann” blir matchet.

#inkludere
#inkludere
ved hjelp av navneområdet STD;
int main ()

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

Funksjonen regex_search () returnerer sant hvis det er en kamp og returnerer falsk hvis ingen kamp oppstår. Her tar funksjonen to argumenter: den første er målstrengen, og den andre er regex -objektet. Regex i seg selv er "mann", i dobbeltkjørt. Den første uttalelsen i Main () -funksjonen danner Regex -objektet. Regex er en type, og Reg er regex -objektet. Ovennevnte utdata er "matchet", som "mann" sees i målstrengen. Hvis "mann" ikke ble sett i målet, ville regex_search () ha returnert falsk, og utgangen ville blitt "ikke matchet".

Utgangen fra følgende kode er "ikke matchet":

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

Ikke matchet fordi regex "mann" ikke ble funnet i hele målstrengen, "her er min å lage.""

Mønster

Det vanlige uttrykket, "mann" ovenfor, er veldig enkelt. Regexes er vanligvis ikke så enkle. Regelmessige uttrykk har metakaraktører. Metacharacters er karakterer med spesielle betydninger. En metakarakter er en karakter om karakterer. C ++ Regex Metacharacters er:

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

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

Karakterklasser

Firkantede parenteser

Et mønster kan ha karakterer i firkantede parenteser. Med dette vil en bestemt posisjon i målstrengen samsvare med noen av de firkantede partene sine karakterer. Tenk på følgende mål:

"Katten er i rommet.""
"Bat er i rommet.""
"Rotten er i rommet.""

Regex, [CBR] på ville matche Cat 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

Utvalg av karakterer

Klassen, [CBR] i mønsteret [CBR], ville matche flere mulige karakterer 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", ville det ikke være noen kamp.

Noen muligheter som 'C' eller 'B' eller 'R' eksisterer i et område. Utvalget av sifre, 0 til 9 har 10 muligheter, og mønsteret for det er [0-9]. Utvalget av små alfabeter, A til Z, har 26 muligheter, og mønsteret for det er [A-Z]. Utvalget av store alfabeter, A til Z, har 26 muligheter, og mønsteret for det er [A-Z]. - er ikke offisielt en metakarakter, men innenfor firkantede parenteser vil det indikere et område. Så følgende produserer en kamp:

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

Legg merke til hvordan regexen 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:

if (regex_search ("id6id", regex ("[0123456789]")))
cout << "matched" << endl;

Følgende kode produserer en kamp:

char str [] = "id6ie";
if (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 et område er en klasse. Det kan være tekst til høyre for området eller til venstre for rekkevidden i mønsteret. Følgende kode produserer en kamp:

if (regex_search ("ID2IDPOST-95222 -__ DDELINK__294_3116034780"> 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," er ikke matchet i denne situasjonen.

Som brukt i det vanlige uttrykkets emne (regexes), betyr ordklassen faktisk et sett. Det vil si at en av karakterene i settet er å matche.

Merk: bindestrek - er en metakarakter bare innen firkantede parenteser, noe som indikerer et område. Det er ikke en metakarakter i regexen, utenfor de firkantede parentesene.

Negasjon

En klasse inkludert et område kan negeres. Det vil si at ikke av karakterene i settet (klassen) skal samsvare. Dette er indikert med ^ metakarakteren i begynnelsen av klassemønsteret, like etter åpningsfeltbraketten. Så [^0-9] betyr å matche karakteren i riktig posisjon i målet, som ikke er noen karakter i området, 0 til 9 inklusive. Så følgende kode vil ikke produsere en kamp:

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

Et siffer innenfor området 0 til 9 ble funnet i noen av målstrengposisjonene, “0123456789101112,”; Så det er ingen kamp - negasjon.

Følgende kode produserer en kamp:

if (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å [^a-z] er negasjonen av [A-Z].

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

Andre negasjoner eksisterer.

Matchende hvitespaser

"Eller \ t eller \ r eller \ n eller \ f er en hvitromkarakter. I følgende kode samsvarer regex, "\ n" '\ n' i målet:

if (regex_search ("av linje en.\ r \ nof line to.", regex (" \ n ")))
cout << "matched" << endl;

Matcher et hvilket som helst hvitromskarakter

Mønsteret eller klassen for å matche et hvilket som helst hvitt romkarakter er, [\ t \ r \ n \ f]. I følgende kode er "matchet:

if (regex_search ("One Two", regex ("[\ t \ r \ n \ f]")))
cout << "matched" << endl;

Matcher ethvert ikke-hvittromskarakter

Mønsteret eller klassen for å matche ethvert ikke-hvitt romkarakter er, [^ \ t \ r \ n \ f]. Følgende kode produserer en kamp fordi det ikke er noen hvitrom i målet:

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

Perioden (.) i mønsteret

Perioden (.) i mønsteret samsvarer med enhver karakter inkludert seg selv, bortsett fra \ n, i målet. En kamp produseres i følgende kode:

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

Ingen matchende resulterer i følgende kode fordi målet er "\ n".

if (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

En karakter eller en gruppe tegn kan forekomme mer enn en gang i målstrengen. Et mønster kan samsvare med denne repetisjonen. Metakarakterene, ?, *, +og brukes til å matche repetisjonen i målet. Hvis X er et tegn av interesse i målstrengen, har metakarakterene følgende betydninger:

x*: betyr match 'x' 0 eller flere ganger, jeg.e., Ethvert antall ganger
x+: betyr match 'x' 1 eller flere ganger, i.e., i hvert fall en gang
x? : betyr match 'x' 0 eller 1 gang
x n,: betyr match 'x' minst n eller flere ganger. Legg merke til komma.
x n: match 'x' nøyaktig n ganger
x n, m: match 'x' minst n ganger, men ikke mer enn m ganger.

Disse metakarakterene kalles kvantifiserere.

Illustrasjoner

*

* Samsvarer med den foregående karakteren eller foregående gruppen, null eller flere ganger. “O*” matcher 'O' i “Hund” av målstrengen. Det samsvarer også med "oo" i "bok" og "ser". Regex, “O*” stemmer overens.”. Merk: “O*” samsvarer med “Dig”, der 'O' forekommer null (eller mer) tid.

+

+ Samsvarer med den foregående karakteren eller foregående gruppen, 1 eller flere ganger. Kontrast det med null eller flere ganger for *. Så regex, “E+” matcher 'E' i “Eat”, der 'E' forekommer en gang. “E+” samsvarer også med “EE” i “Sheep”, der 'E' forekommer mer enn en gang. Merk: “E+” vil ikke samsvare med “Dig” fordi i “Dig”, 'E' forekommer ikke minst en gang.

?

De ? Matcher den foregående karakteren eller foregående gruppen, 0 eller 1 gang (og ikke mer). Så, “E?”Matcher“ Dig ”fordi 'E' forekommer i“ Dig ”, null tid. “E?”Samsvarer“ sett ”fordi 'e' forekommer i“ sett ”, en gang. Merk: “E?”Matcher fortsatt“ sauer ”; Selv om det er to 'E -er i "sauer". Det er en nyanse her - se senere.

n,

Dette samsvarer minst med påfølgende repetisjoner av en foregående karakter eller foregående gruppe. Så regex, "e 2," samsvarer med de to 'E -ene i målet, "sauer", og de tre' e i målet "sheeep". “E 2,” samsvarer ikke med “Set”, fordi “Set” bare har en 'E'.

n

Dette samsvarer nøyaktig med påfølgende repetisjoner av en foregående karakter eller foregående gruppe. Så regex, "E 2" samsvarer med de to 'E -ene i målet, "sauer". “E 2” samsvarer ikke med “Set” fordi “Set” bare har en 'E'. Vel, "E 2" samsvarer med to 'E -er i målet, "Sheeep". Det er en nyanse her - se senere.

n, m

Dette samsvarer med flere påfølgende repetisjoner av en foregående karakter eller foregående gruppe, hvor som helst fra N til M, inkludert. Så "E 1,3" samsvarer med ingenting i "Dig", som ikke har "E". Det samsvarer med den ene 'e' i "sett", de to 'e -er i "sauer", de tre' e -er i "sheeep", og tre 'e i "sheeeep". Det er en nyanse på forrige kamp - se senere.

Matchende veksling

Tenk på følgende målstreng på datamaskinen.

“Gården har griser 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 griser i forskjellige størrelser.";
if (regex_search (str, regex ("geit | kanin | gris"))))
cout << "matched" << endl;
ellers
cout << "not matched" << endl;

Koden produserer en kamp. Legg merke til bruken av vekslingskarakteren, |. Det kan være to, tre, fire og flere alternativer. C ++ vil først prøve å matche det første alternativet, "geit", på 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, går C ++ videre til neste posisjon i målet og starter med det første alternativet igjen.

I koden ovenfor er "gris" matchet.

Matchende begynnelse eller slutt

Begynnelse


Hvis ^ er i begynnelsen av regexen, kan begynnelsesteksten til målstrengen matches av regexen. I følgende kode er målet på målet “ABC”, som samsvarer med:

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

Ingen matching finner sted i følgende kode:

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

Her er "ABC" ikke i begynnelsen av målet.

Merk: Circumflex -karakteren, '^', er en metakarakter i starten av regexen, og samsvarer med starten av målstrengen. Det er fremdeles en metakarakter i starten av karakterklassen, der den negerer klassen.

Slutt

Hvis $ er på slutten av regexen, kan sluttteksten til målstrengen matches av regexen. I følgende kode er slutten av målet "XYZ", som er matchet:

if (regex_search ("UVW and XYZ", regex ("xyz $")))
cout << "matched" << endl;

Ingen matching finner sted i følgende kode:

if (regex_search ("UVW og XYZ Final", Regex ("XYZ $")))
cout << "matched" << endl;
ellers
cout << "not matched" << endl;

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

Gruppering

Parenteser kan brukes til å gruppere tegn i et mønster. Tenk på følgende regex:

"En konsert (pianist)"

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

"The (pianisten er bra)"

Her er undergruppen eller understrengen: "Pianist er god".

Understrenger med vanlige deler

En bokholder er en person som tar seg av bøker. Se for deg et bibliotek med en 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 er på datamaskinen. Fortsatt er hans interesse å vite om "bokhylle" eller "bokholder" er til stede i hvilken som helst målstreng som er på datamaskinen. I dette tilfellet kan hans regex være:

"Bokhylle | Bokholder.""

Ved hjelp av veksling.

Legg merke til at "bok", som er vanlig for begge ordene, er skrevet to ganger, med de to ordene i mønsteret. For å unngå å skrive "bok" to ganger, ville regexen bli bedre skrevet som:

"Bok (hylle | keeper)"

Her har gruppen, "hylle | keeper" veksling metakarakteren fortsatt blitt brukt, men ikke for 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". Utgangen fra følgende kode er "matchet":

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

“Bokhylle” og ikke “Bookholder” har blitt matchet.

Icase og multiline regex_constants

Icase

Matching er case sensitiv som standard. Imidlertid kan det gjøres til ensfølsom. For å oppnå dette, bruk regex :: icase konstant, som i følgende kode:

if (regex_search ("tilbakemelding", regex ("feed", regex :: icase)))
cout << "matched" << endl;

Utgangen er "matchet". Så "Tilbakemelding" med store bokstaver 'F' har blitt matchet med "Feed" med små bokstaver 'F'. “Regex :: Icase” er blitt gjort til det andre argumentet fra Regex () konstruktøren. Uten det ville ikke uttalelsen gi en kamp.

Multiline

Tenk på følgende kode:

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

Utgangen er "ikke matchet". Regexen, “^^.*$, ”Samsvarer med målstrengen fra begynnelsen til slutten. “.*”Betyr enhver karakter bortsett fra \ n, null eller flere ganger. Så på grunn av Newline -tegnene (\ n) i målet, var det ingen matching.

Målet er en multiline streng. For '.'For å matche Newline -karakteren, må den konstante "regex :: multiline" fremmes, det andre argumentet fra regex () konstruksjonen. Følgende kode illustrerer dette:

char str [] = "linje 1 \ nline 2 \ nline 3";
if (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 Newline -tegn (\ n), kan Regex_Match () -funksjonen brukes. Denne funksjonen er forskjellig fra regex_search (). Følgende kode illustrerer dette:

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

Det er en kamp her. Legg imidlertid merke til at regex samsvarer med hele målstrengen, og målstrengen ikke har noen '\ 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) strengen og understrengene som matches kan bli kjent med den. Dette objektet er et spesielt utvalg med metoder. Match_results -objekttypen er cmatch (for strenglitteraler).

Skaffe kamper

Tenk på følgende kode:

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

Målstrengen har ordet "kvinne". Produksjonen er "kvinne", som tilsvarer regexen, "w.m.n ”. Hos Index Zero har den spesielle matrisen den eneste kampen, som er "kvinne".

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

Cmatch M;
if (regex_search ("rotta, katten, flaggermusen!", M, Regex (" [bcr] at ")))
cout << m[0] << endl;
cout << m[1] << endl;
cout << m[2] << endl;

Utgangen er "rotte" fra indeksen null. m [1] og m [2] er tomme.

Med alternativer blir bare den første understrengen som finnes i målet, sendt 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;

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

Grupperinger

Når grupper er involvert, går det komplette mønsteret matchet, går inn i Cell Zero av den spesielle matrisen. Den neste understrengen som er funnet går i celle 1; Understrengende følgende 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:

Bookseller
selger
Sel
ler

Merk at gruppen (selger) kommer foran gruppen (SEL).

Matchposisjon

Posisjonen til kamp for hver understreng i CMatch-matrisen kan være kjent. Telling begynner fra den første tegnet til 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:

Bookseller-> 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 imidlertid strengen der erstatningen skjer strengobjektet, ikke strengen bokstavelig. Så strengbiblioteket må inkluderes i programmet. Illustrasjon:

#inkludere
#inkludere
#inkludere
ved hjelp av navneområdet STD;
int main ()

String str = "Her kommer mannen min. Der går mannen din.";
String 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 for funksjonen er målet, det andre er regex -objektet, og det tredje er erstatningsstrengen. Funksjonen returnerer en ny streng, som er målet, men har erstatningen. Utgangen er:

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

Konklusjon

Det vanlige uttrykket bruker mønstre for å matche underlag i målsekvensstrengen. Mønstre har metakarakter. Vanlige brukte funksjoner for C ++ vanlige uttrykk, er: regex_search (), regex_match () og regex_replace (). En regex er et mønster i dobbeltkjørt. 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.