{ "cells": [ { "cell_type": "markdown", "id": "ordered-wrestling", "metadata": {}, "source": [ "![Logo 1](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech1.jpg)\n", "
\n", "

Komputerowe wspomaganie tłumaczenia

\n", "

13,14. Korekta pisowni [laboratoria]

\n", "

Rafał Jaworski (2021)

\n", "
\n", "\n", "![Logo 2](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech2.jpg)" ] }, { "cell_type": "markdown", "id": "featured-afghanistan", "metadata": {}, "source": [ "Współczesne programy typu CAT nie mogą obyć się bez korektora pisowni. Na bieżąco kontrolują one pisownię wyrazów po stronie docelowej, czyli tam, gdzie tłumacz wpisuje tłumaczenie. Jest to niezwykle istotne w sytuacji, gdy język docelowy nie jest dla tłumacza językiem ojczystym. Co więcej, badania wykazują, iż korekta pisowni wydatnie zmniejsza liczbę błędów w każdych scenariuszach." ] }, { "cell_type": "markdown", "id": "seventh-genre", "metadata": {}, "source": [ "Co poprawia korekta pisowni? Słowa. Tylko lub aż słowa. Program dokonujący korekty pisowni przegląda tekst słowo po słowie i sprawdza, czy należy ono do słownika. Jeśli nie, sygnalizowany jest błąd oraz, jeśli to możliwe, podawane sugestie poprawy. Co istotne, korektor pisowni nie zajmuje się szeregiem błędów, które mieszczą się w dziedzinie korekty gramatycznej, w tym:\n", "* interpunkcją\n", "* powtórzeniami wyrazów\n", "* stylistyką." ] }, { "cell_type": "markdown", "id": "sticky-society", "metadata": {}, "source": [ "Aby zaimplementować korektor pisowni bez wątpienia potrzebny jest słownik. Skorzystajmy ze słownika, który znajdziemy w folderze data, pochodzącego z narzędzia Hunspell. Jest on spakowany - użyjmy techniki czytania z archiwum zip bez rozpakowywania. Poniższy kod wypisze fragment ze środka słownika." ] }, { "cell_type": "code", "execution_count": 2, "id": "familiar-terrace", "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "kalecząc\n", "kaledonidy\n", "kaledoński\n", "kalefaktor\n", "kalejdofon\n", "kalejdoskop\n", "kalejdoskopowość\n", "kalejdoskopowy\n", "kaleka\n", "kaleki\n", "kalema\n", "kalendarium\n", "kalendarz\n", "kalendarzowy\n", "kalendarzyk\n", "kalendy\n", "kalenica\n", "kalenicowy\n", "kalepin\n", "kalesonki\n", "kalesony\n" ] } ], "source": [ "from zipfile import ZipFile\n", "\n", "with ZipFile('data/hunspell_pl.zip') as zipped_dictionary:\n", " with zipped_dictionary.open('hunspell_pl.txt') as dictionary_file:\n", " count = 0\n", " for line_bytes in dictionary_file:\n", " count += 1\n", " if count >= 100000 and count <= 100020:\n", " line = line_bytes.decode('utf-8')\n", " print(line.rstrip())" ] }, { "cell_type": "markdown", "id": "dominant-insurance", "metadata": {}, "source": [ "Miejmy na uwadze, że powyższy słownik zawiera tylko formy podstawowe słowa, np. zawiera słowo \"kalendarz\", ale nie zawiera \"kalendarze\", \"kalendarza\", \"kalendarzy\" itp. " ] }, { "cell_type": "markdown", "id": "single-brighton", "metadata": {}, "source": [ "Algorytm korekty pisowni na podstawie słownika powinien działać według następujących kroków:\n", "1. Wczytanie słownika do zbioru (set)\n", "2. Podział tekstu do korekty na słowa (podział po spacji)\n", "3. Dla każdego słowa wypisać, czy jest ono poprawne (znajduje się w słowniku) czy nie." ] }, { "cell_type": "markdown", "id": "needed-watson", "metadata": {}, "source": [ "### Ćwiczenie 1: Zaimplementuj podstawowy algorytm korekty pisowni według powyższych wytycznych." ] }, { "cell_type": "code", "execution_count": 33, "id": "economic-southeast", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[True, False, True]" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from zipfile import ZipFile\n", "def correct_text(text):\n", " text = text.rstrip().split(\" \")\n", " isCorrect = [False] * len(text)\n", " with ZipFile('data/hunspell_pl.zip') as zipped_dictionary:\n", " with zipped_dictionary.open('hunspell_pl.txt') as dictionary_file:\n", " for line_bytes in dictionary_file:\n", " bline = line_bytes.decode('utf-8').rstrip()\n", " i = 0\n", " for _ in range(len(text)):\n", " if bline == text[i]:\n", " isCorrect[i] = True\n", " i += 1\n", " \n", " return isCorrect\n", "\n", "correct_text(\"Nadia jestr super\")" ] }, { "cell_type": "markdown", "id": "endless-slide", "metadata": {}, "source": [ "To jednak oczywiście nie wszystko. Do tej pory mamy funkcjonalność sygnalizowania słów błędnych, ale każdy dobry korektor pisowni potrafi podać sugestie poprawek. W tym celu musimy stawić czoła następującemu problemowi - wygenerowanie listy słów podobnych do danego słowa błędnego, które znajdują się w słowniku." ] }, { "cell_type": "markdown", "id": "adult-freight", "metadata": {}, "source": [ "W pierwszej kolejności musimy zdefiniować podobieństwo między wyrazami. Posłuży do tego dobrze nam znana odległość Levenshteina - wyrazy podobne to takie, dla których dystans Levenshteina jest niewielki (np. równy 1 lub 2). Teraz brakuje tylko algorytmu wyszukiwania wyrazów w danym słowniku, które znajdują się niedaleko (w sensie Levenshteina) danego błędnego słowa." ] }, { "cell_type": "markdown", "id": "everyday-things", "metadata": {}, "source": [ "Rozważmy następujący algorytm: dla danego słownika $D$ i błędnego słowa $w \\notin D$:\n", "1. Wygeneruj zbiór $L_1(w)$ wszystkich słów, których odległość Levenshteina od $w$ wynosi 1.\n", "2. Wyznacz zbiór $S_1(w)=L_1(w) \\cap D$\n", "3. Wyznacz zbiór $L_2(w)=\\bigcup_{v \\in L_1(w)} L_1(v)$\n", "4. Wyznacz zbiór $S_2(w)=L_2(w) \\cap D$\n", "5. Zwróć jako listę sugestii: $S_1 \\cup S_2$" ] }, { "cell_type": "markdown", "id": "industrial-convert", "metadata": {}, "source": [ "### Ćwiczenie 2: Napisz funkcję do generowania zbioru $L_1(w)$ - wszystkich słów znajdujących się w odległości Levenshteina 1 od danego słowa w." ] }, { "cell_type": "code", "execution_count": 62, "id": "built-sally", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'coda',\n", " 'doda',\n", " 'koda',\n", " 'moda',\n", " 'roda',\n", " 'soda',\n", " 'wada',\n", " 'weda',\n", " 'wodan',\n", " 'wola',\n", " 'wota',\n", " 'woza',\n", " 'woła',\n", " 'wóda',\n", " 'węda'}" ] }, "execution_count": 62, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from zipfile import ZipFile\n", "\n", "def L1(w):\n", " w.lower()\n", " word_len = len(w)\n", " words = set()\n", " with ZipFile('data/hunspell_pl.zip') as zipped_dictionary:\n", " with zipped_dictionary.open('hunspell_pl.txt') as dictionary_file:\n", " for line_bytes in dictionary_file:\n", " cost = 0\n", " bline = line_bytes.decode('utf-8').rstrip().lower()\n", " if len(bline) < word_len - 1 or len(bline) > word_len + 1:\n", " continue\n", " elif len(bline) == word_len:\n", " for i in range(word_len):\n", " if cost > 1:\n", " continue\n", " if w[i] != bline[i]:\n", " cost += 1\n", " if cost == 1:\n", " words.add(bline)\n", " else:\n", " if w in bline:\n", " words.add(bline)\n", " \n", " return words\n", "\n", "L1(\"woda\")" ] }, { "cell_type": "markdown", "id": "wireless-uncle", "metadata": {}, "source": [ "### Ćwiczenie 3: Napisz funkcję do generowania sugestii poprawek dla danego słowa według opisanego wcześniej algorytmu." ] }, { "cell_type": "code", "execution_count": 69, "id": "coordinated-cooperation", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'jeść', 'ujeść', 'zjeść'}" ] }, "execution_count": 69, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def generate_suggestions(w):\n", " S1 = L1(w)\n", " S2 = set()\n", " for word in S1:\n", " sugestions = L1(word)\n", " for sug in sugestions:\n", " S2.add(sug)\n", " return set.union(S1, S2).difference({w})\n", "\n", "generate_suggestions(\"teść\")" ] } ], "metadata": { "author": "Rafał Jaworski", "email": "rjawor@amu.edu.pl", "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "lang": "pl", "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.12.1" }, "subtitle": "13,14. Korekta pisowni", "title": "Komputerowe wspomaganie tłumaczenia", "year": "2021" }, "nbformat": 4, "nbformat_minor": 5 }