modelowanie-jezykowe-aitech-cw/wyk/01_Jezyk.ipynb
Jakub Pokrywka 5a32294cc8 refactor
2022-03-06 19:21:08 +01:00

820 lines
20 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"![Logo 1](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech1.jpg)\n",
"<div class=\"alert alert-block alert-info\">\n",
"<h1> Modelowanie języka </h1>\n",
"<h2> 1. <i>Język i jego zapis</i> [wykład]</h2> \n",
"<h3> Filip Graliński (2022)</h3>\n",
"</div>\n",
"\n",
"![Logo 2](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech2.jpg)\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Język — różne perspektywy\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Słowo wstępne\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"W matematyce istnieją dwa spojrzenia na rzeczywistość: ciągłe i dyskretne.\n",
"\n",
"Otaczająca nas rzeczywistość fizyczna jest z natury ciągła\n",
"(przynajmniej jeśli nie operujemy w mikroskali), lecz język\n",
"jest dyskretnym wyłomem w ciągłej rzeczywistości.\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Lingwistyka matematyczna\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Przypomnijmy sobie definicję języka przyjętą w lingwistyce\n",
"matematycznej, w kontekście, na przykład, teorii automatów.\n",
"\n",
"****Alfabetem**** nazywamy skończony zbiór symboli.\n",
"\n",
"****Łańcuchem**** (****napisem****) nad alfabetem $\\Sigma$ nazywamy dowolny, skończony,\n",
"ciąg złożony z symboli z $\\Sigma$.\n",
"\n",
"****Językiem**** nazywamy dowolny, skończony bądź nieskończony, zbiór łańcuchów.\n",
"\n",
"W tym formalnym ujęciu językami są na przykład następujące zbiory:\n",
"\n",
"- $\\{\\mathit{poniedziałek},\\mathit{wtorek},\\mathit{środa},\\mathit{czwartek},\\mathit{piątek},\\mathit{sobota},\\mathit{niedziela}\\}$\n",
"- $\\{\\mathit{ab},\\mathit{abb},\\mathit{abbb},\\mathit{abbbb},\\ldots\\}$\n",
"\n",
"To podejście, z jednej strony oczywiście nie do końca się pokrywa się z potocznym\n",
"rozumieniem słowa *język*, z drugiej kojarzy nam się z takimi\n",
"narzędziami informatyki jak wyrażenia regularne, automaty skończenie\n",
"stanowe czy gramatyki języków programowania.\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"abbb"
]
}
],
"source": [
"import regex as re\n",
"rx = re.compile(r'ab+')\n",
"\n",
"rx.search('żabbba').group(0)"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"abbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
]
}
],
"source": [
"import rstr\n",
"\n",
"rstr.xeger(r'ab+')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Ujęcie probabilistyczne\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Na tym wykładzie przyjmiemy inną perspektywą, częściowo ciągłą, opartą\n",
"na probabilistyce. Język będziemy definiować poprzez ****rozkład\n",
"prawdopodobieństwa****: sensownym wypowiedziom czy tekstom będziemy\n",
"przypisywać stosunkowe wysokie prawdopodobieństwo, „ułomnym” tekstom — niższe (być może zerowe).\n",
"\n",
"Na ogół nie mamy jednak do czynienia z językiem jako takim tylko z\n",
"jego przybliżeniami, ****modelami**** (model może być lepszy lub gorszy,\n",
"ale przynajmniej powinien być użyteczny…). Formalnie $M$ nazywamy\n",
"modelem języka (nad skończonym alfabetem $\\Sigma$), jeśli określa dyskretny rozkład prawdopodobieństwa $P_M$:\n",
"\n",
"$$P_M \\colon \\Sigma^{*} \\rightarrow [0,1].$$\n",
"\n",
"Rzecz jasna, skoro mamy do czynienia z rozkładem prawdopodobieństwa, to:\n",
"\n",
"$$\\sum_{\\alpha \\in \\Sigma^{*}} P_M(\\alpha) = 1.$$\n",
"\n",
"Jeśli $M$ ma być modelem języka polskiego, oczekiwalibyśmy, że dla\n",
"napisów:\n",
"\n",
"- $z_1$ — *W tym stanie rzeczy pan Ignacy coraz częściej myślał o Wokulskim.*\n",
"- $z_2$ — *Po wypełniony zbiornik pełny i należne kwotę, usłyszała w attendant*\n",
"- $z_3$ — *xxxxyźźźźźit backspace hoooooooooop x y z*\n",
"\n",
"zachodzić będzie:\n",
"\n",
"$$ P_M(z_1) > P_M(z_2) > P_M(z_3). $$\n",
"\n",
"****Pytanie**** Jakiej konkretnie wartości prawdopodobieństwa\n",
"spodziewalibyśmy się dla zdania *Dzisiaj rano kupiłem w piekarni sześć bułek*\n",
"dla sensownego modelu języka polskiego?\n",
"\n",
"Moglibyśmy sprowadzić tę definicję języka do tej „dyskretnej”, tzn.\n",
"moglibyśmy przyjąć, że łańcuch $\\alpha$ należy do języka wyznaczonego\n",
"przez model $M$, jeśli $P_M(\\alpha) > 0$.\n",
"\n",
"****Pytanie**** Czy moglibyśmy w ten sposób opisać język nieskończony? Czy może istnieć\n",
"dyskretny rozkład prawdopodobieństwa dla nieskończonego zbioru?\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Co jest symbolem?\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Model języka daje rozkład prawdopodobieństwa nad zbiorem łańcuchów\n",
"opartym na skończonym alfabecie, tj. zbiorze symboli. W praktyce\n",
"alfabet nie musi być zgodny z potocznym czy językoznawczym rozumieniem\n",
"tego słowa. To znaczy alfabet może być zbiorem znaków (liter), ale\n",
"modelować język możemy też przyjmując inny typ symboli: sylaby,\n",
"morfemy (cząstki wyrazów) czy po prostu całe wyrazy.\n",
"\n",
"Powinniśmy przy tym pamiętać, że, koniec końców, w pamięci komputera\n",
"wszelkiego rodzaju łańcuchy są zapisywane jako ciągi zer i jedynek — bitów.\n",
"Omówmy pokrótce techniczną stronę modelowania języka.\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Kodowanie znaków\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Cóż może być prostszego od pliku tekstowego?\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" Ala ma kota.\n",
"\n",
"Komputer nic nie wie o literach.\n",
"\n",
"… w rzeczywistości operuje tylko na liczbach …\n",
"\n",
"… czy raczej na zerach i jedynkach …\n",
"\n",
"… a tak naprawdę na ciągłym sygnale elektrycznym …\n",
"\n",
"![img](./01_Jezyk/digitalsignal.jpg)\n",
"\n",
"… zera i jedynki są w naszej głowie …\n",
"\n",
"… co jest dziwne, *naprawdę* dziwne …\n",
"\n",
"… ale nikt normalny się tym nie przejmuje.\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Jak zakodować literę?\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Zakodowanie pikseli składających się na kształtu (****glyfu****) litery A\n",
"*oczywiście* nie jest dobrym pomysłem.\n",
"\n",
"![img](./01_Jezyk/raster.png)\n",
"\n",
"Nie, potrzebujemy *arbitralnego* kodowania dla wszystkich możliwych\n",
"kształtów litery A (*w naszych głowach*): A, $\\mathcal{A}$,\n",
"$\\mathbb{A}$, $\\mathfrak{A}$ powinny otrzymać ten sam kod, powiedzmy 65\n",
"(binarnie: 1000001).\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### ASCII\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ASCII to 7-bitowy (****nie**** 8-bitowy!) system kodowania znaków.\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0: \u0000\n",
"1: \u0001\n",
"2: \u0002\n",
"3: \u0003\n",
"4: \u0004\n",
"5: \u0005\n",
"6: \u0006\n",
"7: \u0007\n",
"8: \b\n",
"9:\n",
"10:\n",
"\n",
"11: \u000b",
"\n",
"12: \f",
"\n",
"13:\n",
"14: \u000e\n",
"15: \u000f\n",
"16: \u0010\n",
"17: \u0011\n",
"18: \u0012\n",
"19: \u0013\n",
"20: \u0014\n",
"21: \u0015\n",
"22: \u0016\n",
"23: \u0017\n",
"24: \u0018\n",
"25: \u0019\n",
"26: \u001a\n",
"27: \u001b\n",
"28: \u001c",
"\n",
"29: \u001d",
"\n",
"30: \u001e",
"\n",
"31: \u001f\n",
"32:\n",
"33: !\n",
"34: \"\n",
"35: #\n",
"36: $\n",
"37: %\n",
"38: &\n",
"39: '\n",
"40: (\n",
"41: )\n",
"42: *\n",
"43: +\n",
"44: ,\n",
"45: -\n",
"46: .\n",
"47: /\n",
"48: 0\n",
"49: 1\n",
"50: 2\n",
"51: 3\n",
"52: 4\n",
"53: 5\n",
"54: 6\n",
"55: 7\n",
"56: 8\n",
"57: 9\n",
"58: :\n",
"59: ;\n",
"60: <\n",
"61: =\n",
"62: >\n",
"63: ?\n",
"64: @\n",
"65: A\n",
"66: B\n",
"67: C\n",
"68: D\n",
"69: E\n",
"70: F\n",
"71: G\n",
"72: H\n",
"73: I\n",
"74: J\n",
"75: K\n",
"76: L\n",
"77: M\n",
"78: N\n",
"79: O\n",
"80: P\n",
"81: Q\n",
"82: R\n",
"83: S\n",
"84: T\n",
"85: U\n",
"86: V\n",
"87: W\n",
"88: X\n",
"89: Y\n",
"90: Z\n",
"91: [\n",
"92: \\\n",
"93: ]\n",
"94: ^\n",
"95: _\n",
"96: `\n",
"97: a\n",
"98: b\n",
"99: c\n",
"100: d\n",
"101: e\n",
"102: f\n",
"103: g\n",
"104: h\n",
"105: i\n",
"106: j\n",
"107: k\n",
"108: l\n",
"109: m\n",
"110: n\n",
"111: o\n",
"112: p\n",
"113: q\n",
"114: r\n",
"115: s\n",
"116: t\n",
"117: u\n",
"118: v\n",
"119: w\n",
"120: x\n",
"121: y\n",
"122: z\n",
"123: {\n",
"124: |\n",
"125: }\n",
"126: ~\n",
"127: "
]
}
],
"source": [
"for code in range(0, 128):\n",
" print(f'{code}: {chr(code)}')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Jak zejść na poziom bitów?\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Linux — wiersz poleceń\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Linux command line:\n",
"\n",
" $ echo 'Ala ma kota' > file.txt\n",
" $ hexdump -C file.txt\n",
" 00000000 41 6c 61 20 6d 61 20 6b 6f 74 61 0a |Ala ma kota.|\n",
" 0000000c\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Edytor tekstu (Emacs)\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"![img](./01_Jezyk/hexl-mode.png)\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Uwaga!\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- kiedy dzieje się coś dziwnego, sprawdź, co tak *naprawdę* jest w pliku\n",
"- ASCII jest 7-bitowym kodowaniem (128 znaków)\n",
" - choć zazwyczaj uzupełnionym (ang. *padded*) do 8 bitów\n",
" - nie mów plik *plik ASCII*, kiedy masz na myśli *prosty/czysty plik tekstowy* (ang. *plain text file*)\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Higiena plików tekstowych\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Piekło końca wiersza\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"![img](./01_Jezyk/dante.jpg)\n",
"\n",
"Więcej na [https://re-research.pl/pl/post/2017-01-28-00042-anatomia-pliku-tekstowego-2.html](https://re-research.pl/pl/post/2017-01-28-00042-anatomia-pliku-tekstowego-2.html)\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Dobre rady\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- żadnych niepotrzebnych spacji na końcu wiersza\n",
"\n",
"- żadnych niepotrzebnych pustych wierszy na końcu pliku\n",
"\n",
"- … ale ostatni wiersz powinien zakończyć się znakiem końca wiersza\n",
"\n",
"- nie używać znaków tabulacji (zamiast tego 4 spacje)\n",
" - wyjątek: pliki TSV\n",
" - wyjątek: pliki Makefile\n",
"\n",
"- uwaga na niestandardowe spacje i dziwne znaki o zerowej długości\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Unikod\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ASCII obejmuje 128 znaków: litery alfabetu łacińskiego (właściwie angielskiego),\n",
"cyfry, znaki interpunkcyjne, znaki specjalne itd.\n",
"\n",
"Co z pozostałymi znakami? Polskimi ogonkami, czeskimi haczykami,\n",
"francuskimi akcentami, cyrylicą, koreańskim alfabetem, chińskimi\n",
"znakami, rongorongo?\n",
"\n",
"워싱턴, 부산, 삼성\n",
"\n",
"Rozwiązaniem jest Unikod (ang. *Unicode*) system, który przypisuje\n",
"znakom używanym przez ludzkość liczby (kody, ang. *code points*).\n",
"\n",
"| Znak|Kod ASCII|Kod Unikodowy|\n",
"|---|---|---|\n",
"| 9|57|57|\n",
"| a|97|97|\n",
"| ą|-|261|\n",
"| ł|-|322|\n",
"| $\\aleph$|-|1488|\n",
"| ặ|-|7861|\n",
"| ☣|-|9763|\n",
"| 😇|-|128519|\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### UTF-8\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Kody znaków są pojęciem abstrakcyjnym. Potrzebujemy konkretnego ****kodowania****\n",
"by zamienić kody w sekwencję bajtów. Najpopularniejszym kodowaniem jest UTF-8.\n",
"\n",
"W kodowaniu UTF-8 znaki zapisywane za pomocą 1, 2, 3, 4, 5 lub 6 bajtów\n",
"(w praktyce — raczej to 4 bajtów).\n",
"\n",
"| Znak|Kod Unikodowy|Szesnastkowo|UTF-8 (binarnie)|\n",
"|---|---|---|---|\n",
"| 9|57|U+0049|01001001|\n",
"| a|97|U+0061|01100001|\n",
"| ą|261|U+0105|11000100:10000101|\n",
"| ł|322|U+0142|11000101:10000010|\n",
"| $\\aleph$|1488|U+05D0|11010111:10010000|\n",
"| ặ|7861|U+1EB7|11100001:10111010:10110111|\n",
"| ☣|9763|U+2623|11100010:10011000:10100011|\n",
"| 😇|128519|U+1f607|11110000:10011111:10011000:10000111|\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### UTF-8 — ogólny schemat zamiany kodu na bajty\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- 0x00 do 0x7F 0xxxxxxx,\n",
"- 0x80 do 0x7FF 110xxxxx 10xxxxxx\n",
"- 0x800 do 0xFFFF — 1110xxxx 10xxxxxx 10xxxxxx\n",
"- 0x10000 do 0x1FFFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx\n",
"- 0x200000 do 0x3FFFFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx\n",
"- 0x4000000 do 0x7FFFFFFF 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx\n",
"\n",
"Symbol x oznacza znaczący bit.\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### *Źdźbło* to ile bajtów w UTF-8?\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Jeśli wczytać jako wiersz w języku C, 11 bajtów!\n",
"\n",
"![img](./01_Jezyk/zdzblo.png)\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Dlaczego UTF-8 jest doskonałym systemem kodowania?\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- wstecznie kompatybilny z ASCII\n",
" - plik ASCII jest poprawnym plikiem UTF-8\n",
"- nie zajmuje dużo miejsca\n",
" - chyba że w tekście jest dużo „dziwnych” znaków\n",
"- proste grepowanie działa\n",
" - `grep UAM text-in-utf8.txt` zadziała\n",
" - ale nawet nie próbuj: `grep SRPOL text-in-utf16.txt`\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Porady\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- zawsze używaj UTF-8\n",
" - bądź asertywny! jeśli w pracy każą używać czegoś innego — rezygnuj z pracy\n",
" - **NIE** używaj innych unikodowych kodowań: UTF-16, UTF-32, UCS-2\n",
" - **NIE** używaj nieunikodowych systemów kodowania\n",
" - ISO-8859-2, Windows-1250, Mazovia, IEA Świerk, …\n",
"- uwaga na pułapki UTF-8\n",
" - ustalenie długości napisu w znakach wymaga przejścia znak po znaku\n",
" - jeśli napis w kodowaniu UTF-8 zajmuje 9 bajtów, ile to znaków?\n",
" 3, 4, 5, 6, 7, 8 lub 9!\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### **NIE** używaj sekwencji BOM\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"![img](./01_Jezyk/evil-bom.png)\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Unikod/UTF-8 a języki programowania\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Pamiętaj, żeby być konsekwentnym!\n",
"\n",
"- kodowanie kodu źródłowego (literały!)\n",
" - czasami podawane na początku pliku\n",
" - … albo brane z ustawień *locale*\n",
" - … albo — domyślnie — UTF-8 (w nowszych językach programowania)\n",
"- kodowanie standardowego wejścia/wyjścia i plików\n",
"- jak sekwencje bajtów są interpretowane w czasie działania programu?\n",
" - *Źdźbło* jest łańcuchem złożonym z 6 czy 9 elementów??\n",
" - 9 bajtów\n",
" - 6 kodów\n",
" - `\"Źdźbło\"[1]` …\n",
" - `d`\n",
" - … albo śmieci\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Python 2\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/python2\n",
"# -*- coding: utf-8 -*-\n",
"import sys\n",
"for line in sys.stdin:\n",
" line = line.decode('utf-8').rstrip()\n",
" if \"źdźbło\".decode('utf-8') in line:\n",
" print len(line), ' ', line"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Python3\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/python3\n",
"import sys\n",
"for line in sys.stdin:\n",
" line = line.strip()\n",
" if \"źdźbło\" in line:\n",
" print(len(line), ' ', line)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Uwaga: zakładając, że zmienna środowiskowa `LANG` jest ustawiona na UTF-8.\n",
"\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.2"
},
"org": null
},
"nbformat": 4,
"nbformat_minor": 1
}