Základy regulárního výrazu v C ++

Regular Expression Basics C

Zvažte následující větu v uvozovkách:

'Tady je můj muž.'

Tento řetězec může být uvnitř počítače a uživatel může chtít vědět, zda obsahuje slovo man. Pokud má slovo muž, pak může chtít změnit slovo muž na ženu; takže řetězec by měl číst:



'Tady je moje žena.'

Existuje mnoho dalších takových tužeb od uživatele počítače; některé jsou složité. Pravidelný výraz, zkráceně, regex, je předmětem řešení těchto problémů počítačem. C ++ přichází s knihovnou s názvem regex. Program C ++ pro zpracování regexu by tedy měl začínat:



#zahrnout

#zahrnout

pomocí oboru názvů std;

Tento článek vysvětluje základy regulárního výrazu v C ++.



Obsah článku

Základy regulárního výrazu

Regex

Řetězec jako Tady je můj muž. výše je cílová sekvence nebo cílový řetězec nebo jednoduše cíl. muž, který byl hledán, je regulární výraz, nebo jednoduše regex.

Vhodný

K shodě prý dochází, když se nachází hledané slovo nebo fráze. Po spárování může dojít k výměně. Například poté, co je muž umístěn výše, může být nahrazen ženou.

Jednoduché párování

Následující program ukazuje, jak se shoduje slovo muž.



#zahrnout

#zahrnout

pomocí oboru názvů std;

inthlavní()
{

regulární výraz reg('muž');
-li (regex_search('Tady je můj muž.',reg))
náklady<< 'uzavřeno' <<endl;
jiný
náklady<< 'neodpovídající' <<endl;

vrátit se 0;
}

Funkce regex_search () vrací true, pokud existuje shoda, a vrací false, pokud nedojde k žádné shodě. Zde funkce přebírá dva argumenty: první je cílový řetězec a druhý je objekt regexu. Samotný regex je ve dvojitých uvozovkách „muž“. První příkaz ve funkci main () tvoří objekt regexu. Regex je typ a reg je objekt regexu. Výše uvedený program má výstup „uzavřený“, protože v cílovém řetězci je vidět „muž“. Pokud by v cíli nebylo vidět 'man', regex_search () by se vrátilo false a výstup by byl 'neodpovídající'.

Výstup následujícího kódu není shodný:

regulární výraz reg('muž');
-li (regex_search('Tady je moje tvorba.',reg))
náklady<< 'uzavřeno' <<endl;
jiný
náklady<< 'neodpovídající' <<endl;

Nebylo nalezeno, protože v celém cílovém řetězci nebyl nalezen výraz „muž“ s výrazem „Tady je moje tvorba“.

Vzor

Regulární výraz, muž výše, je velmi jednoduchý. Regexy obvykle nejsou tak jednoduché. Regulární výrazy mají metaznaky. Metaznaky jsou znaky se zvláštním významem. Metacharakter je postava o postavách. Metaznaky regexu C ++ jsou:

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

Regex, s nebo bez metaznaků, je vzor.

Třídy postav

Hranaté závorky

Vzor může mít znaky v hranatých závorkách. Díky tomu by konkrétní pozice v cílovém řetězci odpovídala znakům v hranatých závorkách. Zvažte následující cíle:

'Kočka je v místnosti.'

'Netopýr je v místnosti.'

'Krysa je v místnosti.'

Regex, [cbr] at by odpovídal kočce v prvním cíli. To by odpovídalo pálce ve druhém cíli. Ve třetím terči by to odpovídalo krysám. Důvodem je, že kočka nebo netopýr nebo krysa začínají „c“ nebo „b“ nebo „r“. Následující segment kódu to ilustruje:

regulární výraz reg('[cbr] ve');
-li (regex_search('Kočka je v místnosti.',reg))
náklady<< 'uzavřeno' <<endl;
-li (regex_search('Netopýr je v místnosti.',reg))
náklady<< 'uzavřeno' <<endl;
-li (regex_search('Krysa je v místnosti.',reg))
náklady<< 'uzavřeno' <<endl;

Výstupem je:

uzavřeno

uzavřeno

uzavřeno

Rozsah postav

Třída, [cbr] ve vzoru [cbr], by odpovídala několika možným znakům v cíli. V cíli by odpovídalo „c“ nebo „b“ nebo „r“. Pokud cíl nemá žádné z „c“ nebo „b“ nebo „r“, za kterými následuje at, nedojde k žádné shodě.

Některé možnosti jako „c“ nebo „b“ nebo „r“ existují v rozsahu. Rozsah číslic 0 až 9 má 10 možností a vzor pro to je [0-9]. Rozsah malých abeced, od a do z, má 26 možností a vzor pro to je [a-z]. Rozsah velkých abeced, od A do Z, má 26 možností a vzor pro to je [A-Z]. - není oficiálně metacharacter, ale v hranatých závorkách by to znamenalo rozsah. Následující tedy vytváří shodu:

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

náklady<< 'uzavřeno' <<endl;

Všimněte si, jak byl regex vytvořen jako druhý argument. K shodě dochází mezi číslicí, 6 v rozsahu, 0 až 9 a 6 v cíli, ID6id. Výše uvedený kód je ekvivalentní:

-li (regex_search('ID6id',regex('[0123456789]')))

náklady<< 'uzavřeno' <<endl;

Následující kód vytvoří shodu:

charp[] = 'ID6iE';

-li (regex_search(p,regex('[a-z]')))

náklady<< 'uzavřeno' <<endl;

Všimněte si, že první argument zde je řetězcová proměnná a ne řetězcový literál. Shoda je mezi „i“ v [a-z] a „i“ v ID6iE.

Nezapomeňte, že rozsah je třída. Ve vzoru může být text napravo od rozsahu nebo nalevo od rozsahu. Následující kód vytvoří shodu:

-li (regex_search(„ID2id je ID ',regex('ID [0-9] id')))

náklady<< 'uzavřeno' <<endl;

Shoda je mezi ID [0-9] id a ID2id. Zbytek cílového řetězce je ID, v této situaci není shodný.

Jak se používá v předmětu regulárního výrazu (regexy), slovo třída ve skutečnosti znamená množinu. To znamená, že jedna z postav v sadě se má shodovat.

Poznámka: Spojovník - je metaznak pouze v hranatých závorkách, což označuje rozsah. Není to metacharacter v regulárním výrazu, mimo hranaté závorky.

Negace

Třídu zahrnující rozsah lze negovat. To znamená, že by se neměly shodovat žádné znaky v sadě (třídě). To je indikováno ^ metacharakterem na začátku vzoru třídy, hned za úvodní hranatou závorkou. Takže [^0-9] znamená shodu znaku na příslušné pozici v cíli, což není žádný znak v rozsahu, 0 až 9 včetně. Následující kód tedy nevytvoří shodu:

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

náklady<< 'uzavřeno' <<endl;

jiný

náklady<< 'neodpovídající' <<endl;

Číslici v rozsahu 0 až 9 lze nalézt v jakékoli z cílových pozic řetězce, 0123456789101112 ,; takže neexistuje shoda - negace.

Následující kód vytvoří shodu:

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

náklady<< 'uzavřeno' <<endl;

V cíli nebyla nalezena žádná číslice, ABCDEFGHIJ ,; takže je shoda.

[a-z] je rozsah mimo [^a-z]. A tak [^a-z] je negací [a-z].

[A-Z] je rozsah mimo [^A-Z]. A tak [^A-Z] je negací [A-Z].

Existují i ​​jiné negace.

Odpovídající mezery

‘‘ Nebo t nebo r nebo n nebo f je prázdný znak. V následujícím kódu se regulární výraz n shoduje s n v cíli:

-li (regex_search('Z řádku jedna.' r nZ řádku dva. ',regex(' n')))

náklady<< 'uzavřeno' <<endl;

Odpovídající libovolnému znaku mezery

Vzor nebo třída, která odpovídá libovolnému znaku prázdného místa, je [ t r n f]. V následujícím kódu se shoduje „“:

-li (regex_search('jedna, dvě',regex('[[ t r nF] ')))

náklady<< 'uzavřeno' <<endl;

Odpovídající jakékoli jiné než bílé znaku

Vzor nebo třída, která odpovídá libovolnému znaku bez mezery, je [^ t r n f]. Následující kód vytvoří shodu, protože v cíli není mezera:

-li (regex_search('1234abcd',regex('[^ t r nF] ')))

náklady<< 'uzavřeno' <<endl;

Perioda (.) Ve vzoru

Perioda (.) Ve vzoru odpovídá libovolnému znaku včetně samotného, ​​kromě n, v cíli. V následujícím kódu je vytvořena shoda:

-li (regex_search('1234abcd',regex('.')))

náklady<< 'uzavřeno' <<endl;

V následujícím kódu nejsou žádné odpovídající výsledky, protože cíl je n.

-li (regex_search(' n',regex('.')))

náklady<< 'uzavřeno' <<endl;

jiný

náklady<< 'neodpovídající' <<endl;

Poznámka: Uvnitř třídy znaků se hranatými závorkami nemá tečka žádný zvláštní význam.

Odpovídající opakování

Znak nebo skupina znaků se může v cílovém řetězci vyskytovat více než jednou. Vzor se může shodovat s tímto opakováním. Metaznaky?, *, +A {} se používají k porovnání opakování v cíli. Pokud x je znak zájmu v cílovém řetězci, pak mají metaznaky následující významy:

X*:znamená zápas'X' 0nebo vícekrát,já.A.,libovolný počet opakování

X+:znamená zápas'X' 1nebo vícekrát,já.A.,alespoň jednou

X? :znamená zápas'X' 0nebo1 čas

X{n,}:znamená zápas'X'alespoň n nebo vícekrát.Poznámkačárka.

X{n} :zápas'X'přesně n krát

X{n,m}:zápas'X'alespoň nkrát,ale ne více než mkrát.

Tyto metaznaky se nazývají kvantifikátory.

Ilustrace

*

* Odpovídá předchozímu znaku nebo předchozí skupině, nula nebo vícekrát. o* odpovídá „o“ u psa cílového řetězce. To také odpovídá oo v knize a pohledu. Regex, o* odpovídá boooo v The animal booooed .. Poznámka: o* odpovídá digu, kde ‘o’ nastává nulový (nebo více) čas.

+

+ Odpovídá 1 nebo vícekrát předchozímu znaku nebo předchozí skupině. Kontrastujte to nula nebo vícekrát pro *. Takže regex, e+ odpovídá 'e' v jídle, kde se 'e' vyskytuje jednou. e+ také odpovídá ee u ovcí, kde se „e“ vyskytuje více než jednou. Poznámka: e+ nebude odpovídat kopání, protože v digu se „e“ nevyskytuje alespoň jednou.

?

The? odpovídá předchozímu znaku nebo předchozí skupině, 0 nebo 1krát (a ne více). Tak co? odpovídá kopání, protože „e“ se vyskytuje v kopání, nulový čas. E? odpovídá nastaveným, protože ‘e’ se vyskytuje v sadě, jednou. Poznámka: e? stále odpovídá ovcím; ačkoli jsou dvě „e“ v ovcích. Zde je nuance - viz později.

{n,}

To odpovídá alespoň n po sobě jdoucích opakování předchozího znaku nebo předchozí skupiny. Regex, e {2,} tedy odpovídá dvěma „e v cíli, ovci, a třem„ e “v cílové ovci. e {2,} neodpovídá množině, protože množina má pouze jedno „e“.

{n}

To odpovídá přesně n po sobě jdoucích opakování předchozího znaku nebo předchozí skupiny. Regex, e {2} tedy odpovídá dvěma „e“ v cíli, ovci. e {2} neodpovídá množině, protože sada má pouze jedno ‘e‘. E {2} odpovídá dvěma „e“ v cíli, ovce. Zde je nuance - viz později.

{n, m}

To odpovídá několika po sobě následujícím opakováním předchozího znaku nebo předchozí skupiny, kdekoli od n do m, včetně. E {1,3} tedy neodpovídá ničemu v digu, který nemá žádné ‚e‘. Odpovídá jednomu „e“ v sadě, dvěma „e“ v ovcích, třem „e“ v ovcích a třem „e“ v ovcím. V posledním zápase je nuance - viz později.

Odpovídající alternace

Zvažte následující cílový řetězec v počítači.

Na farmě jsou prasata různých velikostí.

Programátor může chtít vědět, zda tento cíl má kozu, králíka nebo prase. Kód by byl následující:

charp[] = 'Na farmě jsou prasata různých velikostí.';

-li (regex_search(p,regex('koza | králík | prase')))

náklady<< 'uzavřeno' <<endl;

jiný

náklady<< 'neodpovídající' <<endl;

Kód vytvoří shodu. Všimněte si použití alternačního znaku |. Mohou existovat dvě, tři, čtyři a další možnosti. C ++ se nejprve pokusí porovnat první alternativu, kozu, na každé pozici znaku v cílovém řetězci. Pokud to s kozou neuspěje, zkusí další alternativu, králíka. Pokud u králíka neuspěje, zkusí další alternativu, prase. Pokud prase selže, pak se C ++ přesune na další pozici v cíli a začne znovu s první alternativou.

Ve výše uvedeném kódu se prase shoduje.

Odpovídající začátek nebo konec

Začátek


Pokud ^ je na začátku regexu, pak může být počáteční text cílového řetězce shodný s regexem. V následujícím kódu je začátek cíle abc, který odpovídá:

-li (regex_search('abc a def',regex('^ abc')))

náklady<< 'uzavřeno' <<endl;

V následujícím kódu neprobíhá shoda:

-li (regex_search('Ano, abc a def',regex('^ abc')))

náklady<< 'uzavřeno' <<endl;

jiný

náklady<< 'neodpovídající' <<endl;

Zde abc není na začátku cíle.

Poznámka: Znak cirkumflexu „^“ je metacharacter na začátku regexu, který odpovídá začátku cílového řetězce. Je to stále metacharacter na začátku třídy znaků, kde třídu neguje.

Konec

Pokud je $ na konci regexu, pak může být koncový text cílového řetězce shodný s regexem. V následujícím kódu je konec cíle xyz, který odpovídá:

-li (regex_search('uvw a xyz',regex('xyz $')))

náklady<< 'uzavřeno' <<endl;

V následujícím kódu neprobíhá shoda:

-li (regex_search('uvw a xyz final',regex('xyz $')))

náklady<< 'uzavřeno' <<endl;

jiný

náklady<< 'neodpovídající' <<endl;

Tady xyz není na konci cíle.

Seskupení

K seskupení znaků ve vzoru lze použít závorky. Zvažte následující regex:

'koncert (pianista)'

Tato skupina je pianista obklopený metaznaky (a). Je to vlastně podskupina, zatímco koncert (pianista) je celá skupina. Zvažte následující:

'Pianista je dobrý'

Zde je podskupina nebo podřetězce, pianista je dobrý.

Dílčí řetězce se společnými součástmi

Účetní je osoba, která se stará o knihy. Představte si knihovnu s účetní a knihovnou. Předpokládejme, že je v počítači jeden z následujících cílových řetězců:

„Knihovna má knihovnu, kterou obdivuji.“;

„Tady je účetní.“;

„Účetní pracuje s policí.“;

Předpokládejme, že zájmem programátora není vědět, která z těchto vět je v počítači. Přesto je jeho zájmem vědět, zda je v jakémkoli cílovém řetězci v počítači přítomen regál nebo účetní. V tomto případě jeho regex může být:

'regál | účetní.'

Pomocí střídání.

Všimněte si, že kniha, která je společná pro obě slova, byla napsána dvakrát ve dvou slovech ve vzoru. Abyste se vyhnuli psaní knihy dvakrát, regex by byl lépe napsán jako:

'kniha (polička | strážce)'

Zde skupina, polička | strážce Metacharakter střídání byl stále používán, ale ne na dvě dlouhá slova. Byl použit pro dvě koncové části dvou dlouhých slov. C ++ považuje skupinu za entitu. C ++ tedy bude hledat poličku nebo držitele, který přijde hned po knize. Výstup následujícího kódu odpovídá:

charp[] = 'Knihovna má knihovnu, kterou obdivuji.';

-li (regex_search(p,regex('kniha (polička | strážce)')))

náklady<< 'uzavřeno' <<endl;

byly uzavřeny regály a nikoli účetní.

Icase a víceřádkové regex_constants

icase

Při párování se ve výchozím nastavení rozlišují velká a malá písmena. Může však být citlivý na malá a velká písmena. K dosažení tohoto cíle použijte konstantu regex :: icase, jako v následujícím kódu:

-li (regex_search('Zpětná vazba',regex('krmit',regex::icase)))

náklady<< 'uzavřeno' <<endl;

Výstup je shodný. Zpětná vazba s velkými písmeny „F“ tedy odpovídala kanálu s malými písmeny „f“. regex :: icase byl vytvořen jako druhý argument konstruktoru regex (). Bez toho by prohlášení nevytvořilo shodu.

Víceřádkový

Zvažte následující kód:

charp[] = 'řádek 1 nřádek 2 nřádek 3 ';

-li (regex_search(p,regex('^. * $')))

náklady<< 'uzavřeno' <<endl;

jiný

náklady<< 'neodpovídající' <<endl;

Výstup není shodný. Regulární výraz ^.*$ Odpovídá cílovému řetězci od jeho začátku do konce. .* znamená jakýkoli znak kromě n, nula nebo vícekrát. Kvůli znakům nového řádku ( n) v cíli tedy nedošlo k žádné shodě.

Cílem je víceřádkový řetězec. Aby se „.“ Shodovalo se znakem nového řádku, musí být vytvořen konstantní regex :: multiline, druhý argument konstrukce regex (). Následující kód to ilustruje:

charp[] = 'řádek 1 nřádek 2 nřádek 3 ';

-li (regex_search(p,regex('^. * $',regex::víceřádkový)))

náklady<< 'uzavřeno' <<endl;

jiný

náklady<< 'neodpovídající' <<endl;

Odpovídající řetězci celého cíle

Aby se shodoval s celým cílovým řetězcem, který nemá znak nového řádku ( n), lze použít funkci regex_match (). Tato funkce se liší od regex_search (). Následující kód to ilustruje:

charp[] = 'první druhý třetí';

-li (regex_match(p,regex('.*druhý.*')))

náklady<< 'uzavřeno' <<endl;

Tady je shoda. Všimněte si však, že regex odpovídá celému cílovému řetězci a cílový řetězec nemá žádné ' n'.

Objekt match_results

Funkce regex_search () může mít argument mezi cílem a objektem regexu. Tento argument je objekt match_results. Lze s ním znát celý shodný (část) řetězec a odpovídající podřetězce. Tento objekt je speciální pole s metodami. Typ objektu match_results je cmatch (pro řetězcové literály).

Získávání zápasů

Zvažte následující kód:

charp[] = 'Žena, kterou jsi hledal!';

cmatch m;

-li (regex_search(p,m,regex('w.m.n')))

náklady<<m[0] <<endl;

Cílový řetězec má slovo žena. Výstupem je žena ‘, což odpovídá regexu, w.m.n. Na indexu nula obsahuje speciální pole jedinou shodu, kterou je žena.

S možnostmi třídy je do speciálního pole odeslán pouze první dílčí řetězec nalezený v cíli. Následující kód to ilustruje:

cmatch m;

-li (regex_search('Krysa, kočka, netopýr!',m,regex('[bcr] v')))

náklady<<m[0] <<endl;

náklady<<m[1] <<endl;

náklady<<m[2] <<endl;

Výstupem je krysa od nulového indexu. m [1] a m [2] jsou prázdné.

U alternativ je do zvláštního pole odeslán pouze první dílčí řetězec nalezený v cíli. Následující kód to ilustruje:

-li (regex_search('Králík, koza, prase!',m,regex('koza | králík | prase')))

náklady<<m[0] <<endl;

náklady<<m[1] <<endl;

náklady<<m[2] <<endl;

Výstupem je králík z indexu nula. m [1] a m [2] jsou prázdné.

Seskupení

Když jsou zapojeny skupiny, kompletní uzavřený vzor přejde do buňky nula speciálního pole. Další nalezený dílčí řetězec přejde do buňky 1; následující dílčí řetězec přejde do buňky 2; a tak dále. Následující kód to ilustruje:

-li (regex_search(„Nejlepší knihkupec současnosti!“,m,regex('kniha ((sel) (ler))')))

náklady<<m[0] <<endl;

náklady<<m[1] <<endl;

náklady<<m[2] <<endl;

náklady<<m[3] <<endl;

Výstupem je:

knihkupec

prodejce

buňka

číst

Všimněte si, že skupina (prodejce) je před skupinou (sel).

Pozice zápasu

Pozici shody pro každý dílčí řetězec v poli cmatch lze znát. Počítání začíná od prvního znaku cílového řetězce na pozici nula. Následující kód to ilustruje:

cmatch m;

-li (regex_search(„Nejlepší knihkupec současnosti!“,m,regex('kniha ((sel) (ler))')))

náklady<<m[0] << '->' <<m.pozice(0) <<endl;

náklady<<m[1] << '->' <<m.pozice(1) <<endl;

náklady<<m[2] << '->' <<m.pozice(2) <<endl;

náklady<<m[3] << '->' <<m.pozice(3) <<endl;

Všimněte si použití vlastnosti position s indexem buňky jako argumentu. Výstupem je:

knihkupec->5

prodejce->9

buňka->9

číst->12

Hledat a nahradit

Nové slovo nebo frázi může nahradit shodu. K tomu slouží funkce regex_replace (). Tentokrát je však řetězec, kde dochází k nahrazení, řetězec, nikoli řetězcový literál. Knihovna řetězců tedy musí být součástí programu. Ilustrace:

#zahrnout

#zahrnout

#zahrnout

pomocí oboru názvů std;

inthlavní()
{
řetězec str= „Tady, můj muž. Tady jde tvůj muž. ';
řetězec newStr=regex_replace(p,regex('muž'), 'žena');
náklady<<novýStr<<endl;

vrátit se 0;
}

Funkce regex_replace (), jak je zde kódována, nahrazuje všechny shody. Prvním argumentem funkce je cíl, druhým je objekt regexu a třetím je náhradní řetězec. Funkce vrací nový řetězec, který je cílem, ale má náhradu. Výstupem je:

Tady přichází moje žena. Tam jde tvoje žena.

Závěr

Regulární výraz používá vzory k přiřazení podřetězců v řetězci cílové sekvence. Vzory mají metaznaky. Běžně používané funkce pro regulární výrazy C ++ jsou: regex_search (), regex_match () a regex_replace (). Regex je vzor ve dvojitých uvozovkách. Tyto funkce však berou jako argument nejen objekt regexu, ale nejen regex. Než ho tyto funkce mohou použít, musí být z regexu vytvořen regexový objekt.