{ "cells": [ { "cell_type": "markdown", "source": [ "# Języki formalne i złożoność obliczeniowa\n", "## Część 1: Wprowadzenie do biblioteki re\n" ], "metadata": { "collapsed": false }, "id": "f5376d249e31d5aa" }, { "cell_type": "markdown", "source": [ "Wyrażenia regularne będziemy robić na podstawie języka python3. Dokumentacja: https://docs.python.org/3.11/library/re.html\n", "\n", "Użyteczna strona do testowania wyrażeń regularnych: https://regex101.com/\n" ], "metadata": { "collapsed": false }, "id": "ce091d4ec144df32" }, { "cell_type": "markdown", "source": [ "# Podstawowe funkcje" ], "metadata": { "collapsed": false }, "id": "35428280eb1f704" }, { "cell_type": "markdown", "source": [ "## Match\n", "match - zwraca dopasowanie od początku stringa" ], "metadata": { "collapsed": false }, "id": "9674be284007455d" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "import re\n", "wynik = re.match(r'Ala', 'Ala ma kota. Kot ma Alę.')\n", "print(wynik)\n", "print(f\"Dopasowano: '{wynik.group()}', początek: {wynik.start()}, koniec: {wynik.end()}\")\n" ], "metadata": { "collapsed": false }, "id": "fa7637b60ae679b5" }, { "cell_type": "markdown", "source": [ "## Search\n", "search - zwraca pierwsze dopasowanie w napisie\n" ], "metadata": { "collapsed": false }, "id": "626c591ab52a086" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "# search\n", "wynik = re.search(r'ni', 'Może nie najtaniej, ale jako tako.')\n", "\n", "if wynik:\n", " print(f\"Dopasowano: '{wynik.group()}', początek: {wynik.start()}, koniec: {wynik.end()}\")\n", "else:\n", " print('Nie znaleziono szukanego ciągu znaków.')" ], "metadata": { "collapsed": false }, "id": "4f5d7077a85b7108" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "tekst = \"Kto zakłóca ciszę nocną musi ponieść karę: 100 batów!\"\n", "\n", "wzorzec = re.compile('ci')\n", "\n", "wynik = wzorzec.search(tekst)\n", "\n", "if wynik:\n", " print(f\"Dopasowano: '{wynik.group()}', początek: {wynik.start()}, koniec: {wynik.end()}\")\n", "else:\n", " print('Nie znaleziono szukanego ciągu znaków.')" ], "metadata": { "collapsed": false }, "id": "b9da286f8d6936fb" }, { "cell_type": "markdown", "source": [ "## findall\n", "findall - zwraca listę wszystkich dopasowań\n" ], "metadata": { "collapsed": false }, "id": "600b87dd6af48c04" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "# findall\n", "wzorzec = re.compile('o')\n", "\n", "wynik = wzorzec.findall(tekst)\n", "\n", "if len(wynik) > 0:\n", " print(type(wynik))\n", " print(f'Dopasowano: {wynik}')\n", "else:\n", " print(f'{wynik} Nie znaleziono szukanego ciągu znaków.')" ], "metadata": { "collapsed": false }, "id": "37a93d9d61c6178d" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "wzorzec = re.compile('o')\n", "\n", "wynik = wzorzec.finditer(tekst)\n", "for w in wynik:\n", " print(type(w))\n", " print(f'Dopasowano: \"{w.group()}\", początek: {w.start()}, koniec: {w.end()}')" ], "metadata": { "collapsed": false }, "id": "3232906632de2fe1" }, { "cell_type": "markdown", "source": [ "*Uwaga*: pobierając z iteratora elementy, usuwamy je, nie można zatem ponownie się do nich odwołać." ], "metadata": { "collapsed": false }, "id": "62e8a0370ee58827" }, { "cell_type": "markdown", "source": [ "## Użycie przedrostka 'r' w wyrażeniach regularnych w Pythonie\n", "\n", "W Pythonie przedrostek `r` przed łańcuchem znaków oznacza \"surowy\" łańcuch znaków (ang. *raw string*). Dlaczego jest to przydatne w kontekście wyrażeń regularnych?\n", "\n", "Wyrażenia regularne często używają znaków specjalnych, takich jak `\\d`, `\\w`, `\\b` itp. W standardowych łańcuchach znaków w Pythonie, znaki te mają specjalne znaczenie. Na przykład, `\\t` oznacza tabulację, a `\\n` oznacza nową linię.\n", "\n", "Jeśli chcemy użyć takiego wyrażenia regularnego w Pythonie, musielibyśmy podwajać znaki ukośnika, aby uniknąć konfliktu z wbudowanymi sekwencjami ucieczki w łańcuchach znaków, np. `\\\\d`, `\\\\w`." ], "metadata": { "collapsed": false }, "id": "6342ff85cd5fc35a" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "# Bez użycia surowego łańcucha znaków\n", "result1 = re.findall(\"\\\\d+\", \"123 abc 456\")\n", "print(result1)\n", "\n", "# Używając surowego łańcucha znaków\n", "result2 = re.findall(r\"\\d+\", \"123 abc 456\")\n", "print(result2)\n" ], "metadata": { "collapsed": false }, "id": "b09fa3103ec18719" }, { "cell_type": "markdown", "source": [ "## sub\n", "Kolejną użyteczną metodą jest sub(), która pozwala na zmianę wzorca na inny ciąg znaków:" ], "metadata": { "collapsed": false }, "id": "e9e3f41e90bbd746" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "wzorzec = re.compile(r'ni')\n", "\n", "zmieniony = wzorzec.sub('Ni!', tekst)\n", "print(zmieniony)" ], "metadata": { "collapsed": false }, "id": "af633211d7faca67" }, { "cell_type": "markdown", "source": [ "## split\n", "split - dzieli napis na podstawie wzorca" ], "metadata": { "collapsed": false }, "id": "ea9205aa03ed7476" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "wzorzec = re.compile(r' ')\n", "\n", "wynik = wzorzec.split(tekst)\n", "print(f'Uzyskano {len(wynik)} wyniki/ów.')\n", "for w in wynik:\n", " print(w)" ], "metadata": { "collapsed": false }, "id": "71dc3b254a93f31c" }, { "cell_type": "markdown", "source": [ "# Metaznaki\n", "[] - zbiór znaków\n", "\n", ". - jakikolwiek znak\n", "\n", "^ - początek napisu\n", "\n", "$ - koniec napisu\n", "\n", "? - znak występuje lub nie występuje\n", "\n", "\\* - zero albo więcej pojawień się\n", "\n", "\\+ - jeden albo więcej pojawień się\n", "\n", "{} - dokładnie tyle pojawień się\n", "\n", "| - lub\n", "\n", "() - grupa\n", "\n", "\\ - znak ucieczki\n", "\n", "\\d digit\n", "\n", "\\D nie digit\n", "\n", "\\s whitespace\n", "\n", "\\S niewhitespace" ], "metadata": { "collapsed": false }, "id": "4b16abb6848f09ae" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "wzorzec = re.compile(r'.')\n", "print(wzorzec.findall(tekst))" ], "metadata": { "collapsed": false }, "id": "ac6669cac4f52d27" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "# jeden lub wiecej / zero lub wiecej\n", "\n", "tekst = \"BCAAABGTAABBBCCTTSAGG4324242\"\n", "print(f'Łańcuch: {tekst}')\n", "wzorzec = re.compile(r'X+')\n", "print(f'Jeden lub więcej X: {wzorzec.findall(tekst)}')\n", "wzorzec = re.compile(r'X*')\n", "print(f'Zero lub więcej X: {wzorzec.findall(tekst)}')" ], "metadata": { "collapsed": false }, "id": "634e4b66a5081f97" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "# zero lub jeden\n", "\n", "print(f'Łańcuch: {tekst}')\n", "wzorzec = re.compile(r'.?')\n", "print(wzorzec.findall(tekst))\n", "wzorzec = re.compile(r'.?T')\n", "print(wzorzec.findall(tekst))" ], "metadata": { "collapsed": false }, "id": "44195e00a81b23fb" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "print(f'Łańcuch: {tekst}')\n", "wzorzec = re.compile(r'A+')\n", "print(f'Dopasowanie zachłanne: {wzorzec.findall(tekst)}')\n", "wzorzec = re.compile(r'A+?')\n", "print(f'Dopasowanie leniwe: {wzorzec.findall(tekst)}')" ], "metadata": { "collapsed": false }, "id": "ea861a33e942d42a" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "print(f'Łańcuch: {tekst}')\n", "\n", "# dokladnie 3 dopasowania\n", "wzorzec = re.compile(r'A{3}')\n", "print(f'{wzorzec.findall(tekst)}')\n", "\n", "# pomiedzy 2 i 3 dopasowania\n", "wzorzec = re.compile(r'A{2,3}')\n", "print(f'{wzorzec.findall(tekst)}')\n", "\n", "# 2 lub wiecej dopasowan\n", "wzorzec = re.compile(r'A{2,}')\n", "print(f'{wzorzec.findall(tekst)}')\n", "\n", "# 3 lub mniej dopasowan\n", "wzorzec = re.compile(r'A{,3}')\n", "print(f'{wzorzec.findall(tekst)}')" ], "metadata": { "collapsed": false }, "id": "751272b81731af36" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "# poczatek lub koniec lancucha\n", "\n", "tekst = \"Ale pięknie pachnie! Maciek, co gotujesz?\"\n", "\n", "# poczatek lancucha\n", "wzorzec = re.compile(r'^Ale')\n", "print(f'{wzorzec.findall(tekst)}')\n", "\n", "# poczatek lancucha\n", "wzorzec = re.compile(r'^ale')\n", "print(f'{wzorzec.findall(tekst)}')\n", "\n", "# koniec lancucha\n", "wzorzec = re.compile(r'Ale$')\n", "print(f'{wzorzec.findall(tekst)}')\n", "\n", "# koniec lancucha + znak ucieczki\n", "wzorzec = re.compile(r'gotujesz\\?$')\n", "print(f'{wzorzec.findall(tekst)}')" ], "metadata": { "collapsed": false }, "id": "97bcd3ff7cc3913" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "# grupy znakow\n", "wzorzec = re.compile(r'[A-Z]')\n", "print(f'Duże litery: {wzorzec.findall(tekst)}')\n", "\n", "wzorzec = re.compile(r'[a-z]')\n", "print(f'Małe litery: {wzorzec.findall(tekst)}')\n", "\n", "wzorzec = re.compile(r'[A-z]')\n", "print(f'Małe i duże litery: {wzorzec.findall(tekst)}')\n", "\n", "wzorzec = re.compile(r'[aeiou]')\n", "print(f'Samogłoski: {wzorzec.findall(tekst)}')" ], "metadata": { "collapsed": false }, "id": "ee099e6e1e5e2f80" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "# wzorzec(?=X) - dopasowanie, jeśli po nim występuje X\n", "\n", "tekst = \"ACABADAHSAIIIQIIINSAODIANSAAGAGAGGGGPAAG\"\n", "\n", "print(f'Łańcuch: {tekst}')\n", "wzorzec = re.compile(r'G+(?=A)')\n", "print(f'{wzorzec.findall(tekst)}')" ], "metadata": { "collapsed": false }, "id": "dd6351952639ef42" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "tekst = \"Ale się zrobiła świąteczna atmosfera.\"\n", "wzorzec = re.compile(r'Ale|świąteczna|zrobiła')\n", "print(f'{wzorzec.findall(tekst)}')" ], "metadata": { "collapsed": false }, "id": "c7f3e1b9d16c91db" }, { "cell_type": "markdown", "source": [ "## Znaki specjalne\n", "\n", "\\s\t- biały znak\n", "\n", "\\S\t- nie-biały znak\n", "\n", "\\d\t- cyfra\n", "\n", "\\D\t- nie-cyfra\n", "\n", "\\w\t- znaki alfanumeryczne (litery i cyfry) oraz\n", " \n", "\\W\t- znaki nie-alfanumeryczne i nie\n", " \n", "\\b\t- początek lub koniec ,,słowa’’\n", " \n", "\\B\t- nie początek lub koniec ,,słowa''\n", "\n", "[a-z]\t- małe litery\n", "\n", "[A-Z]\t- wielkie litery\n", "\n", "[0-9]\t- cyfry\n" ], "metadata": { "collapsed": false }, "id": "c1a7435b7887f5c2" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "wzorzec = re.compile(r'\\w+')\n", "print(f'Wyrazy: {wzorzec.findall(tekst)}')\n" ], "metadata": { "collapsed": false }, "id": "3b1b1f147233455d" }, { "cell_type": "markdown", "source": [ "## Część II: Zadania praktyczne\n", "\n", "### Zadanie 1: Wyszukiwanie numerów telefonu\n", "\n", "Napisz wyrażenie regularne, które znajdzie wszystkie numery telefonu w tekście. Zakładamy, że numer telefonu ma format `xxx-xxx-xxx` lub `xxx xxx xxx`.\n" ], "metadata": { "collapsed": false }, "id": "e0670d19927add2b" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "tekst = \"\"\"\n", "Jan: 123-456-789\n", "Anna: 987 654 321\n", "Karol: 456-789-123\n", "Zbyszek: 53252525342252\n", "Tytus: aaaa666432\n", "\"\"\"\n", "\n", "wzorzec = re.compile(r\"\")\n", "print(f'Numery: {wzorzec.findall(tekst)}')" ], "metadata": { "collapsed": false }, "id": "aecbbf61477429ac" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "tekst = \"\"\"\n", "jan.kowalski@gmail.com\n", "anna.zielinska@amu.edu.pl\n", "karol.nowak@interia.pl\n", "hello world\n", "@test.pl\n", "x@x\n", "fff22@gmail.com\n", "\"\"\"\n", "\n", "wzorzec = re.compile(r\"\")\n", "print(f'Adresy: {wzorzec.findall(tekst)}')" ], "metadata": { "collapsed": false }, "id": "1dcf9585d7b78073" }, { "cell_type": "markdown", "source": [ "# Część III Zadanie domowe\n", "\n", "## Zadanie 1: Wyszukiwanie kodów pocztowych (2 pkt)\n", "Napisz wyrażenie regularne, które znajdzie wszystkie polskie kody pocztowe w tekście. Zakładamy, że kod pocztowy ma format XX-XXX, gdzie X to cyfra.\n", "\n", "## Zadanie 2: Weryfikacja adresu URL (2 pkt)\n", "Zaimplementuj wyrażenie regularne, które sprawdzi, czy dany ciąg jest poprawnym adresem URL. Zakładamy, że adres URL zaczyna się od http:// lub https://, po którym następuje nazwa domeny i opcjonalnie ścieżka.\n", "\n", "## Zadanie 3: Weryfikacja numeru PESEL (2 pkt)\n", "Napisz wyrażenie regularne, które sprawdzi, czy dany ciąg jest poprawnym numerem PESEL. PESEL składa się z 11 cyfr.\n", "\n", "## Zadanie 4: Wyszukiwanie tagów HTML (3 pkt)\n", "Zaimplementuj wyrażenie regularne, które znajdzie wszystkie tagi (otwierające i zamykające) w tekście HTML.\n", "\n", "## Zadanie 5: Weryfikacja hasła (4 pkt)\n", "Napisz wyrażenie regularne, które sprawdzi, czy dane hasło spełnia następujące kryteria:\n", "\n", "Ma co najmniej 8 znaków.\n", "\n", "Zawiera co najmniej jedną dużą literę.\n", "\n", "Zawiera co najmniej jedną małą literę.\n", "\n", "Zawiera co najmniej jedną cyfrę.\n", "\n", "Zawiera co najmniej jeden ze znaków specjalnych: @, #, $, %, &, *, !.\n", "\n", "\n", "Rozwiązania zadań należy wysłać na adres email: **miczar1@amu.edu.pl** z tytułem: **[DJFZ][NrIndeksu] Zadanie domowe Zajęcia 2**. Jako załącznik należy wysłać 5 plików .py (zadanie1.py, zadanie2.py itd.) z rozwiązaniem. Skrpyty na wejściu mają przyjmować plik tekstowy `in.txt` a następnie zapisać rezultaty do pliku `out.txt` (każdy pasujący element to jeden wiersz) lub (True/False jak w poprzednim zadaniu) Przykładowe wywołanie skryptu: `python zadanie1.py in.txt`." ], "metadata": { "collapsed": false }, "id": "ae6ffce379f9676d" } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.6" } }, "nbformat": 4, "nbformat_minor": 5 }