C ++

Základy regulárních výrazů v C ++

Základy regulárních výrazů v 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, jestli má slovo „man“. Pokud má slovo muž, může chtít změnit slovo „muž“ na „žena“; aby řetězec měl číst:

„Tady je moje žena."

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

#zahrnout
#zahrnout
pomocí jmenného prostoru std;

Tento článek vysvětluje základy regulárních výrazů v jazyce C++.

Obsah článku

  • Základy regulárního výrazu
  • Vzor
  • Třídy znaků
  • Odpovídající mezery
  • Období (.) ve vzoru
  • Odpovídající opakování
  • Odpovídající střídání
  • Odpovídající začátek nebo konec
  • Seskupení
  • Icase a multiline regex_constants
  • Přiřazení celého cíle
  • Objekt match_results
  • Pozice zápasu
  • Hledat a nahradit
  • Závěr

Základy regulárního výrazu

Regulární výraz

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

Vhodný

Ke shodu se říká, že nastane, 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 je slovo „muž“ spárováno.

#zahrnout
#zahrnout
pomocí jmenného prostoru std;
int main ()

regex reg ("muž");
if (regex_search ("Tady je můj muž.".", reg))
cout << "matched" << endl;
jiný
cout << "not matched" << endl;
návrat 0;

Funkce regex_search () vrátí hodnotu true, pokud existuje shoda, a vrátí hodnotu false, pokud nedojde k žádné shodě. Zde funkce přijímá dva argumenty: první je cílový řetězec a druhý je regexový objekt. Samotný regulární výraz je „muž“ v uvozovkách. První příkaz ve funkci main () tvoří objekt regex. Regex je typ a reg je objekt regex. Výstup výše uvedeného programu je „uzavřen“, protože „man“ je vidět v cílovém řetězci. Pokud by „man“ nebyl v cíli vidět, regex_search () by vrátil hodnotu false a výstup by „nebyl shodný“.

Výstup následujícího kódu je „neodpovídá“:

regex reg ("muž");
if (regex_search ("Tady je moje tvorba.", reg))
cout << "matched" << endl;
jiný
cout << "not matched" << endl;

Nebylo uzavřeno, protože „muž“ s regulárním výrazem nebyl nalezen v celém cílovém řetězci: „Tady je moje tvorba."

Vzor

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

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

Regulární výraz, s metaznaky nebo bez nich, je vzor.

Třídy znaků

Hranaté závorky

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

„Kočka je v místnosti."
„Netopýr je v místnosti."
„Krysa je v místnosti."

Regulární výraz, [cbr] v by odpovídal kočce v prvním cíli. Shodovalo by se to s pálkou ve druhém cíli. Shoduje se s krysou ve třetím cíli. Je to proto, že „kočka“ nebo „netopýr“ nebo „krysa“ začíná na „c“ nebo „b“ nebo „r“. Následující segment kódu to ilustruje:

regex reg ("[cbr] at");
if (regex_search ("Kočka je v místnosti.", reg))
cout << "matched" << endl;
if (regex_search ("Netopýr je v místnosti.", reg))
cout << "matched" << endl;
if (regex_search ("Krysa je v místnosti.", reg))
cout << "matched" << endl;

Výstupem je:

uzavřeno
uzavřeno
uzavřeno

Rozsah znaků

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

V rozsahu existují některé možnosti jako „c“ nebo „b“ nebo „r“. Rozsah číslic od 0 do 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 něj 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ě metaznak, ale v hranatých závorkách by to znamenalo rozsah. Následující tedy vytváří shodu:

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

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

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

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

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

Všimněte si, že první argument je zde řetězcová proměnná, nikoli ř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:

if (regex_search ("ID2id is ID ", regex (" ID [0-9] id ")))
cout << "matched" << endl;

Shoda je mezi „ID [0-9] id“ a „ID2id“. Zbytek cílového řetězce „je ID“ se v této situaci neshoduje.

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

Poznámka: Pomlčka - je metaznak pouze v hranatých závorkách, což označuje rozsah. Nejde o metaznak 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 označeno ^ metaznakem na začátku vzoru třídy, hned za úvodní hranatou závorkou. [^ 0-9] znamená tedy shodu znaku na příslušné pozici v cíli, což není žádný znak v rozsahu od 0 do 9 včetně. Následující kód tedy nevytvoří shodu:

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

Číslici v rozsahu 0 až 9 lze nalézt na kterékoli z pozic cílového řetězce, „0123456789101112,“; takže neexistuje žádná shoda - negace.

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

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

V cíli nebyla nalezena žádná číslice „ABCDEFGHIJ“; takže existuje shoda.

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

[A-Z] je rozsah mimo [^ A-Z]. A tak [^ A-Z] je negace [A-Z].

Existují i ​​další negace.

Odpovídající mezery

"nebo \ t nebo \ r nebo \ n nebo \ f je prázdný znak. V následujícím kódu regulární výraz „\ n“ odpovídá cíli „\ n“:

if (regex_search ("Z prvního řádku.\ r \ nz druhého řádku.", regex (" \ n ")))
cout << "matched" << endl;

Odpovídá jakékoli mezeře

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 je „uzavřeno“:

if (regex_search ("jedna dvě", regex ("[\ t \ r \ n \ f]")))
cout << "matched" << endl;

Odpovídá libovolnému znaku jiného než prázdného místa

Vzor nebo třída, která odpovídá libovolnému znaku jiného než bílého místa, je [^ \ t \ r \ n \ f]. Následující kód vytvoří shodu, protože v cíli nejsou žádné mezery:

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

Období (.) ve vzoru

Období (.) ve vzoru odpovídá libovolnému znaku včetně jeho samotného, ​​kromě \ n v cíli. Shoda se vytváří v následujícím kódu:

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

V následujícím kódu nejsou žádné výsledky shody, protože cíl je „\ n“.

if (regex_search ("\ n", regex (".")))
cout << "matched" << endl;
jiný
cout << "not matched" << endl;

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

Odpovídající opakování

Znak nebo skupina znaků se v cílovém řetězci může vyskytnout více než jednou. Tomuto opakování může odpovídat vzor. 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, mají metaznaky následující význam:

x *: znamená shodu 'x' 0 nebo vícekrát, tj.E., libovolný počet opakování
x +: znamená shodu 'x' 1 nebo vícekrát, tj.E., alespoň jednou
X? : znamená shodu 'x' 0 nebo 1 krát
x n,: znamená shodu 'x' alespoň n nebo vícekrát. Všimněte si čárky.
x n: shoda 'x' přesně n krát
x n, m: shoda 'x' alespoň n krát, ale ne více než m krá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“ v „dog“ cílového řetězce. Rovněž odpovídá „oo“ v „knize“ a „hledá“. Regulární výraz „o *“ odpovídá „boooo“ v „The animal booooed.“. Poznámka: „o *“ odpovídá „dig“, kde „o“ nastane nula (nebo více) časů.

+

Znak + odpovídá předchozímu znaku nebo předchozí skupině, 1krát nebo vícekrát. Porovnejte to s nulovým nebo vícekrát za *. Takže regulární výraz „e +“ odpovídá „e“ v „jíst“, kde se „e“ vyskytuje jednou. „E +“ také odpovídá „ee“ v „ovci“, kde se „e“ vyskytuje více než jednou. Poznámka: „e +“ nebude odpovídat „dig“, protože v „dig“ se „e“ nevyskytuje alespoň jednou.

?

The ? odpovídá předchozímu znaku nebo předchozí skupině, 0krát nebo 1krát (a ne více). Takže: „e?“Odpovídá„ dig “, protože„ e “se vyskytuje v„ dig “, v nulovém čase. "E?”Odpovídá“ set ”, protože 'e' se vyskytuje v“ set ”, jednou. Poznámka: „e?„Stále odpovídá„ ovcím “; ačkoli v „ovcích“ jsou dvě. Zde je nuance - viz dále.

n,

To odpovídá alespoň n po sobě jdoucích opakováních předchozího znaku nebo předchozí skupiny. Regex „e 2,“ tedy odpovídá dvěma „e“ v cíli „ovce“ a třem „e“ v cíli „ovce“. „E 2,“ neodpovídá „set“, protože „set“ 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. Regulární výraz „e 2“ tedy odpovídá dvěma e v cíli „ovce“. „E 2“ neodpovídá „set“, protože „set“ má pouze jedno „e“. „E 2“ odpovídá dvěma „e“ v cíli, „ovce“. Zde je nuance - viz dále.

n, m

To odpovídá několika po sobě jdoucí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 „dig“, který nemá „e“. Odpovídá jednomu „e“ v „sadě“, dvěma „e“ v „ovci“, třem „e“ v „ovci“ a třem „e“ v „ovci“. V posledním zápase je nuance - viz dále.

Odpovídající střídání

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

"Farma má prasata různých velikostí.".“

Programátor možná bude chtít vědět, jestli má tento cíl „kozu“, „králíka“ nebo „prase“. Kód by vypadal takto:

char str [] = "Farma má prasata různých velikostí.";
if (regex_search (str, regex ("koza | králík | prase")))
cout << "matched" << endl;
jiný
cout << "not matched" << endl;

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

Ve výše uvedeném kódu je „prase“ shodováno.

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

Začátek


Pokud je ^ na začátku regulárního výrazu, lze počáteční text cílového řetězce porovnat pomocí regulárního výrazu. V následujícím kódu je začátek cíle „abc“, což odpovídá:

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

V následujícím kódu nedojde k žádné shodě:

if (regex_search ("Ano, abc a def", regex ("^ abc")))
cout << "matched" << endl;
jiný
cout << "not matched" << endl;

Tady „abc“ není na začátku cíle.

Poznámka: Znak háčku, ^, je metaznak na začátku regulárního výrazu, který odpovídá začátku cílového řetězce. Je to stále metaznak na začátku třídy znaků, kde tuto třídu neguje.

Konec

Pokud je $ na konci regulárního výrazu, lze koncový text cílového řetězce porovnat pomocí regulárního výrazu. V následujícím kódu je konec cíle „xyz“, který odpovídá:

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

V následujícím kódu nedojde k žádné shodě:

if (regex_search ("uvw and xyz final", regex ("xyz $"))))
cout << "matched" << endl;
jiný
cout << "not matched" << endl;

Zde „xyz“ není na konci cíle.

Seskupení

Závorky lze použít ke seskupení znaků ve vzoru. Zvažte následující regulární výraz:

„koncert (pianista)“

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

„(Pianista je dobrý)“

Podskupina nebo podřetězec je zde „pianista je dobrý“.

Podřetězce se společnými částmi

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

„V knihovně je obdivovaná knihovna.";
„Tady je účetní.";
„Účetní pracuje s policí.";

Předpokládejme, že programátorův zájem 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 libovolném cílovém řetězci v počítači přítomen „regál“ nebo „účetní“. V tomto případě může být jeho regex:

"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. Aby se zabránilo psaní „knihy“ dvakrát, měl by být regex lépe napsán jako:

"kniha (police | chovatel)"

Tady skupina „police | brankář“ Alternativní metaznak se stále používal, ale ne na dvě dlouhá slova. Používá se pro dvě koncové části dvou dlouhých slov. C ++ zachází se skupinou jako s entitou. C ++ tedy bude hledat „poličku“ nebo „chovatele“, který přijde bezprostředně po „knize“. Výstup následujícího kódu je „shodný“:

char str [] = "Knihovna má obdivovanou knihovnu.";
if (regex_search (str, regex ("kniha (police | chovatel)"))))
cout << "matched" << endl;

„Regál“ a nikoli „účetní“ byly spárovány.

Icase a multiline regex_constants

icase

Ve shodě se ve výchozím nastavení rozlišují velká a malá písmena. Lze však rozlišovat velká a malá písmena. K dosažení tohoto cíle použijte konstantu regex :: icase, jako v následujícím kódu:

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

Výstup je „shodný“. Takže „Zpětná vazba“ s velkými písmeny „F“ byla porovnána s „Feedback“ s malými písmeny „f“. „Regex :: icase“ se stal druhým argumentem konstruktoru regex (). Bez toho by prohlášení nepřineslo shodu.

Víceřádkový

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

char str [] = "řádek 1 \ n řádek 2 \ n řádek 3";
if (regex_search (str, regex ("^.* $ ")))
cout << "matched" << endl;
jiný
cout << "not matched" << 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íl je víceřádkový řetězec. K tomu, aby '.„aby se shodoval se znakem nového řádku, musí být vytvořena konstanta„ regex :: multiline “, druhý argument konstrukce regex (). Následující kód to ilustruje:

char str [] = "řádek 1 \ n řádek 2 \ n řádek 3";
if (regex_search (str, regex ("^.* $ ", regex :: multiline)))
cout << "matched" << endl;
jiný
cout << "not matched" << endl;

Shoda s celým řetězcem cíle

Pro shodu 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:

char str [] = "první druhá třetina";
if (regex_match (str, regex (".*druhý.* ")))
cout << "matched" << endl;

Existuje zde 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 přijmout argument mezi cílem a objektem regex. Tento argument je objekt match_results. Lze s ním znát celý uzavřený (část) řetězce a shodné podřetězce. Tento objekt je speciální pole s metodami. Typ objektu match_results je cmatch (pro řetězcové literály).

Získání shody

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

char str [] = "Žena, kterou jste hledali!";
cmatch m;
if (regex_search (str, m, regex ("w.m.n ")))
cout << m[0] << endl;

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

S možnostmi třídy se do zvláštního pole odešle pouze první podřetězec nalezený v cíli. Následující kód to ilustruje:

cmatch m;
if (regex_search ("Krysa, kočka, netopýr!", m, regulární výraz (" [bcr] at ")))
cout << m[0] << endl;
cout << m[1] << endl;
cout << m[2] << endl;

Výstup je „krysa“ z nulového indexu. m [1] a m [2] jsou prázdná.

U alternativ se do zvláštního pole odešle pouze první podřetězec nalezený v cíli. Následující kód to ilustruje:

if (regex_search ("Králík, koza, prase.)!", m, regex (" koza | králík | prase ")))
cout << m[0] << endl;
cout << m[1] << endl;
cout << m[2] << endl;

Výstup je „králičí“ z indexu nula. m [1] a m [2] jsou prázdná.

Seskupení

Pokud jsou zahrnuty skupiny, kompletní vzor se shoduje, přejde do buňky nula speciálního pole. Další nalezený podřetězec přejde do buňky 1; následující podřetězec přejde do buňky 2; a tak dále. Následující kód to ilustruje:

if (regex_search ("Nejlepší knihkupec současnosti."!", m, regex (" kniha ((sel) (ler)) ")))
cout << m[0] << endl;
cout << m[1] << endl;
cout << m[2] << endl;
cout << m[3] << endl;

Výstupem je:

knihkupec
prodejce
sel
ler

Všimněte si, že skupina (prodejce) přichází před skupinou (já).

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;
if (regex_search ("Nejlepší knihkupec současnosti."!", m, regex (" kniha ((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;

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

knihkupec-> 5
prodejce-> 9
sel-> 9
ler-> 12

Hledat a nahradit

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

#zahrnout
#zahrnout
#zahrnout
pomocí jmenného prostoru std;
int main ()

string str = "Tady přichází můj muž. Tady je tvůj muž.";
řetězec newStr = regex_replace (str, regex ("muž"), "žena");
cout << newStr << endl;
návrat 0;

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

"Tady je moje žena.". Tady je tvá žena.“

Závěr

Regulární výraz používá vzory k porovnání 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 (). Regulární výraz je vzor v uvozovkách. Tyto funkce však berou objekt regex jako argument a ne jen regex. Z regulárního výrazu musí být vytvořen objekt regulárního výrazu, než ho mohou tyto funkce používat.

Hry Nejlepší emulátory herních konzolí pro Linux
Nejlepší emulátory herních konzolí pro Linux
Tento článek uvádí seznam populárního softwaru pro emulaci herních konzolí, který je k dispozici pro Linux. Emulace je vrstva softwarové kompatibility...
Hry Nejlepší linuxové distribuce pro hraní her v roce 2021
Nejlepší linuxové distribuce pro hraní her v roce 2021
Operační systém Linux má za sebou dlouhou cestu od svého původního, jednoduchého vzhledu založeného na serveru. Tento OS se v posledních letech nesmír...
Hry Jak zachytit a streamovat vaši herní relaci v systému Linux
Jak zachytit a streamovat vaši herní relaci v systému Linux
V minulosti bylo hraní her považováno pouze za koníček, ale postupem času došlo v herním průmyslu k obrovskému nárůstu z hlediska technologie a počtu ...