% -*-latex-*- % \documentstyle[11pt,romana-]{article} \input{pagesize} \begin{document} \begin{romana} \title{``Corect'' --- un ``spell-check''-er pentru limba rom"an'a} \author{Mihai Budiu --- mihaib@cs.cmu.edu} \date{16 mai 1997} \maketitle \begin{description} \item[Subiect:] un corector de texte pentru limba rom"an'a \item[Cuno'stin'te necesare:] familiaritate cu sisteme de prelucrare a textelor \item[Cuvinte cheie:] spell-check, emacs, ispell, standard, inerna'tionalizare \end{description} \tableofcontents \vspace{0.5cm} Folosind programul {\tt ispell} am construit un pachet de utilitare care u'sureaz'a scrierea 'si corectarea textelor 'in limba rom"an'a. Pachetul este, sper, relativ u'sor de instalat 'si folosit pe platforme Unix, 'si este disponibil oricui f'ar'a restric'tii. Poate fi ob'tinut prin web de la \verb|http://www.cs.cmu.edu/~mihaib/ftp/rom-spell.taz|. 'In acest articol discut 'in oarece detaliu despre una dintre sculele pe care pachetul se bazeaz'a (excelentul program {\tt ispell}) 'si justific unele dintre deciziile pe care le-am luat c'ind am construit pachetul. Pe alocuri divaghez despre importan'ta unui design clar separat, 'si despre func'tia standardelor 'in ziua de azi. \section{Programul {\tt ispell}} {\tt ispell} este software ``free'', deci accesibil oricui. Rolul lui este destul de simplu: analizeaz'a texte 'si indic'a cuvintele a c'aror grafie nu o cunoa'ste, permi't'ind 'in felul acesta corectarea unora dintre erorile de dactilografie. {\tt ispell} vine de la ``fabrican'ti'' cu o 'intreag'a suit'a de programe care permit construirea, manipularea 'si 'intre'tinerea de dic'tionare. {\tt ispell} este prin natura lui un program nu prea inteligent: are la 'indem'in'a un dic'tionar cu {\em toate} cuvintele corecte, iar ceea ce face este s'a caute fiecare cuv'int din textul de corectat 'in dic'tionar. Dac'a g'ase'ste cuv'intul 'il socote'ste bun, dac'a nu, se uit'a 'in dic'tionar dup'a cuvinte care sunt ``apropiate'' ca scriere de cel absent, pe care apoi le propune spre 'inlocuire, presupun'ind ca acel cuv'int a fost gre'sit scris. Ce 'inseamn'a c'a ``dou'a cuvinte sunt aproape'' pentru {\tt ispell}? Un cuv'int este aproape de altul dac'a se poate ob'tine printr-una din urm'atoarele opera'tii: \begin{itemize} \item Ad'augarea unei litere; \item 'Stergerea unei litere; \item Transpunerea a dou'a litere consecutive. \end{itemize} De asemenea, {\tt ispell} poate identifica lipsa unui spa'tiu dintre dou'a cuvinte. De'si un astfel de program nu poate oferi nici o garan'tie 'in producerea de texte corecte, este extrem de eficace 'in a elimina o mare parte dintre erorile tipografice. Chiar faptul c'a {\tt ispell} nu are nici o cuno'stin't'a despre limb'a 'il face foarte util, pentru c'a permite folosirea lui cu texte scrise 'in orice limb'a, cu condi'tia posed'arii unui dic'tionar potrivit. \section{Un principiu de Design} Programe de genul {\tt ispell} exist'a de mult'a vreme 'in lumea Unix (de ex. programul {\tt spell}; to spell = a scrie liter'a cu liter'a). Ceea ce face {\tt ispell} atr'ag'ator este universalitatea lui. {\tt ispell} este un exemplu tipic de program care 'incarneaz'a un foarte important principiu de proiectare 'in calculatoare. Acest principiu se manifest'a 'in separarea dintre {\em mecanism} 'si {\em politic'a} (policy/mechanism). Principiul indic'a faptul c'a un aparat trebuie s'a fie c'it mai universal, ca s'a nu oblige pe cel care 'il folose'ste la anumite feluri de manipulare, care s'a 'ii reduc'a utilitatea. Tehnica este extrem de important'a 'in proiectarea sistemelor de operare, 'si 'in general a programelor care servesc drept unelte\footnote{ Prin antitez'a cu programele care fac ceva util ele 'insele: aplica'tiile.} (de exemplu bibliotecile). Un sistem de operare trebuie de exemplu s'a-'ti ofere toate metodele prin care s'a po'ti controla {\em c'ind} se vor executa programele tale, dar s'a nu impun'a o anumit'a ordine de execu'tie a lor. Sistemul de operare este cel care execut'a programele, dar utilizatorul este cel care indic'a ordinea 'si priorit'a'tile. Un alt exemplu interesant este 'in re'telele de calculatoare: protocoalele de transmisiune a datelor 'stiu s'a mute bi'ti de la un calculator la altul, chiar foarte 'indep'artat. 'In acest caz mecanismul este cel care transport'a datele. Politica de alegere a traseului pe care le urmeaz'a datele este 'ins'a complet separat'a de mecanismul de transport; ea este decis'a de un set complet separat de protocoale, numite protocoale de rutare. Aceast'a flexibilitate permite construirea de protocoale de rutare noi 'si 'inlocuirea celor vechi ``din mers'', f'ar'a a 'intrerupe func'tionarea re'telei 'in vreun fel. Pe scurt: dac'a faci un aparat complicat, nu restr'inge modul 'in care poate fi folosit, ci construie'ste-i suficiente m'inere c'it s'a poat'a fi controlat 'in c'it mai multe feluri. \section{Pachetul pentru limba rom"an'a} Unde trebuie puse m'inerele nu este 'intotdeauna evident. Proiectantul variantei interna'tionale a lui {\tt ispell}, Geoff Kuenning, a studiat cu aten'tie locurile 'in care politica era 'ingropat'a 'in interiorul programului, 'si a 'incercat s'a o extrag'a 'in afar'a. Acest lucru este vizibil utilizatorului prin faptul c'a pentru a folosi {\tt ispell} trebuie s'a scrii o gr'amad'a de fi'siere auxiliare, care controleaz'a modul 'in care lucreaz'a. Ceea ce am 'si f'acut, pentru a putea face {\tt ispell} utilizat cu texte rom"ane'sti. 'In cele ce urmeaz'a voi descrie pe scurt con'tinutul pachetului; aceast'a descriere 'imi va prilejui identificarea por'tiunilor din {\tt ispell} care sunt supuse controlului utilizatorului. \subsection{Fi'sierele de prefixe/sufixe} Principala pies'a din configurarea {\tt ispell} este fi'sierul de afixe. Numele nu este foarte fericit ales, pentru c'a func'tiunea acestuia este, pe l'ing'a de a indica metode de derivare cu prefixe 'si sufixe (care pot fi folosite pentru a comprima dic'tionarele), 'si descrierea parametrilor func'tion'arii lui {\tt ispell}. O prim'a alegere cu care m-am confruntat a fost dac'a dic'tionarele vor con'tine semne diacritice sau nu. Pentru c'a nu m-am putut hot'ar'i, p'in'a la urm'a am construit dou'a configura'tii 'si dou'a dic'tionare, pentru ambele cazuri. Pentru cazul semnelor diacritice a trebuit s'a fac fa't'a urm'atoarelor dou'a decizii: \begin{itemize} \item Dac'a folosesc sau nu noile reguli de scriere ale Academiei cu "a; rezultatul 'il ghici'ti din textul de fa't'a, care este corectat cu {\tt ispell}; \item Cum voi reprezenta semnele diacritice. Aceast'a problem'a este extrem de spinoas'a, 'si 'imi va da prilejul s'a fac o lung'a digresiune: \end{itemize} \subsection{Problema interna'tionaliz'arii} Calculatoarele depind 'intr-o sumedenie de moduri subtile de faptul c'a au fost concepute de oameni care foloseau mai ales limba englez'a (orice istorie a calculatoarelor va recunoa'ste rolul americanilor 'si, ceva mai pu'tin, al englezilor). Modul 'in care sunt prelucrate textele, 'in care sunt afi'sate 'si citite este adesea str'ins legat de caracteristicile speciale ale limbii engleze. De acest lucru 'si-au dat seama cei care au 'incercat s'a universalizeze folosirea calculatoarelor, pentru a le adapta 'si altor na'tii. F'ar'a a avea preten'tia de a trata exhaustiv aceast'a problem'a, s'a arunc'am o privire asupra influen'tei limbii asupra programelor. \subsubsection{Traseul informa'tiei} Pentru a prelucra texte avem trei categorii mari de opera'tii: \begin{itemize} \item Citirea textelor de la tastatur'a; \item Prelucrarea textelor prin feluri'ti algoritmi; \item Afi'sarea (vizualizarea) textelor. \end{itemize} Pentru fiecare din aceste activit'a'ti este responsabil un program distinct. De citirea tastaturii se ocup'a ``driver''-ul de terminal. Acesta are de obicei mai multe func'tiuni: \begin{itemize} \item Deduce combina'tia de taste ap'asat'a; o reprezint'a printr-un 'sir de coduri; \item Traduce codurile la o reprezentare ``standard''; de exemplu c'ind ape'si tasta pe care scrie ``A'' returneaz'a codul ASCII al lui ``a'', care e 97. \item C'iteodat'a face o minim'a editare a textului: de exemplu dac'a ape'si pe DELETE 'sterge un caracter. \end{itemize} 'In func'tie de sistemul de operare, utilizatorul are mai multe op'tiuni la-ndem'in'a pentru a influen'ta driverul: poate s'a citeasc'a direct codurile, s'a influen'teze modul 'in care se face traducerea, s'a evite editarea automat'a textului. Dac'a lucrezi pe un calculator la distan't'a, de exemplu conectat prin {\tt telnet} prin re'tea, lucrurile se complic'a, pentru c'a 'intre driver-ul care cite'ste tastatura (aflat pe calculatorul local) 'si aplica'tia ta (aflat'a la distan't'a) se mai interpun 'inc'a dou'a programe care codific'a fiecare tast'a ap'asat'a: \begin{itemize} \item Programul local de {\tt telnet}, cite'ste tastele de la driver 'si le traduce 'intr-un mod standardizat pentru comunica'tia prin re'tea; \item Programul de la distan't'a, demonul {\tt telnetd}, care prime'ste de la {\tt telnet} codurile standard ale tastelor 'si le traduce pentru ma'sina de acolo. \end{itemize} Afi'sarea textelor este iar'a'si de obicei sarcina unui ``driver''. Dac'a avem de-a face cu un terminal alfa-numeric (sau o fereastr'a care emuleaz'a un astfel de terminal prin software), atunci de obicei driver-ului i se dau secven'te de caractere ASCII, pe care 'stie el cum s'a le afi'seze; din c'ind 'in c'ind i se dau 'si coduri numite ``caractere de control'', care de obicei nu las'a urme pe ecran, ci 'ii spun terminalului {\em cum} s'a manipuleze caracterele ce urmeaz'a. De exemplu putem indica, folosind caractere de control, 'in ce loc pe ecran s'a se scrie urm'atorul caracter ASCII. Care este secven'ta de caractere de control care spune acest lucru depinde de terminal; fiecare fabricant a inventat propriile conven'tii. De c'ind firma Xerox a inventat ecranul grafic (``bitmapped screen''), a deveni un lucru comun ca interfa'ta dintre aplica'tie 'si utilizator s'a nu fie un simplu 'sir de caractere pe care terminalul le afi'seaz'a, ci o matrice mare de punctule'te care pot fi controlate individual. Aplica'tiilor li se pune la 'indem'in'a posibilitatea de a desena orice form'a doresc; foarte frecvent 'ins'a sistemul de operare pune la dispozi'tie func'tii de bilbiotec'a pentru a desena caractere cu felurite forme (``fonturi''). 'In fine, ultimul aspect al prelucr'arii de texte este procesarea lor cu feluri'ti algoritmi: c'aut'ari, sort'ari, tehnoredactare, corectur'a, editare, transmitere de po'st'a electronic'a, etc. Vom reveni pe scurt asupra fazei de prelucrare dup'a ce discut'am despre standardizare. \subsubsection{Standardizarea} Un element cheie 'in interac'tiunea 'intre aceste p'ar'ti (drivere, aplica'tii, biblioteci, sistemul de operare) este faptul c'a {\em toate folosesc aceea'si metod'a de codificare}. C'ind ap'asa'ti tasta ``A'', driverul de tastatur'a 'intoarce 97, iar aplica'tia 'stie c'a a primit un ``A'', pe care 'il poate da bibliotecii de afi'sare, care 'stie c'a trebuie s'a deseneze o astfel de liter'a. Oricine a lucrat pe o tastatur'a prost configurat'a, sau a 'incercat s'a acceseze de la distan'ta o aplica'tie care decodific'a ciudat tastatura, sau a manipulat tabele de translatare ale codurilor, sau a primit mail cu caractere interna'tionale va 'in'telege importan'ta acestei conven'tii. Literei ``A'' i se asociaz'a codul 97 de c'atre codul ASCII (American Standard Code for Information Interchange), care este standardizat de ANSI (American National Standard Institute); e un fel de STAS local. Din fericire, datorit'a domina'tiei SUA 'in arena calculatoarelor, ASCII este practic implementat de toat'a lumea. 'Si organiza'tia mondial'a a standardelor ISO (International Standards Organization) a acceptat ASCII sub numele ISO 646. Codificarea ASCII 'ins'a recomand'a numai 128 de simboluri (din care 32 nici m'acar nu sunt vizibile, ci sunt ``caractere de control''). De 'indat'a ce ie'sim din perimetrul acestora, domne'ste haosul. Pentru caractere pe 8 bi'ti exist'a standardul ISO-8859, care ofer'a o duzin'a de interpret'ari pentru caracterele cu coduri peste 128. Pentru limba rom"an'a cea mai interesant'a interpretare este cea dat'a de ISO-8859-2, numit'a 'si Latin-2, care con'tine toate semnele speciale cu diacritice rom"ane'sti. Problema acum este 'ins'a: 'inainte de a c'adea de acord ce semn este cel cu codul 200, trebuie s'a c'adem de acord ce cod folosim din duzina de variante ISO sau alte variante. Plus c'a fiecare aplica'tie trebuie s'a fie capabil'a s'a interpreteze toate variantele, etc. Tentative de standardizare 'si mai 'indr'azne'te s-au f'acut: un consor'tiu gigant, din care fac parte Microsoft, IBM, Xerox, Sun 'si alte (zeci) de firme din lumea calculatoarelor, a fost 'infiin'tat, pe nume Unicode. Acesta, cu ajutorul a zeci de exper'ti lingvi'sti a propus o standardizare uniform'a a tuturor caracterelor, din toate limbile lumii, folosind pentru aceasta 16 bi'ti pe caracter. Fiecare caracter ar avea astfel o reprezentare unic'a 'si ne-ambigu'a. Dificult'a'tile de 'infr'int sunt enorme; de exemplu trebuie cumva luate 'in considerare standardele na'tionale (cum ar fi cel elaborat de Japonezi) 'si reconciliate. Din p'acate concordia nu este 'inc'a realizat'a, pentru c'a ISO a propus 'in acela'si scop propriul ei standard, diferit de Unicode, pe 32 de bi'ti, numit ISO DIS 10646. Dificultatea la ora asta este deci nu c'a nu exist'a standarde, ci c'a exist'a prea multe. O aplica'tie poate folosi propriile ei conven'tii interne pentru citirea tastaturii/modificare/afi'sare, dar de 'indat'a ce se pune problema {\em schimbului} de informa'tii, absen'ta unui standard unic (sau a unui num'ar mic de standarde) face problema intratabil'a. 'In general, via'ta noastr'a de toate zilele depinde enorm de standarde, 'intr-un fel pe care nici nu-l realiz'am. Dac'a nu am avea standarde trenurile nu ar pute circula pentru c'a ecartamentul ar fi diferit 'in 't'ari diferite (de altfel, la ru'si chiar este mai mare), aparatele electrice nu ar func'tiona dec'it unde au fost proiectate ('si a'sa americanii merg la 110V), ma'sinile ar trebui s'a care benzina de acas'a ca s'a se potriveasc'a cifra octanic'a, am vedea la televizor numai ce ar transmite bunica, cu care folosim aceea'si codificare, etc, etc. \subsubsection{Prelucr'arile pe texte} 'Inainte de a ne 'indep'arta de zona standardelor interna'tionale, s'a mai arunc'am o privire asupra unor 'intreb'ari care sunt legate de reprezentarea caracterelor, 'si al c'aror r'aspuns influen'teaz'a modul 'in care algoritmii vor procesa textele: \begin{itemize} \item Nu toate limbile se scriu 'in aceea'si direc'tie; ebraica se scrie de la dreapta la st'inga, iar japoneza pe vertical'a. C'ind am un text englezesc cu citate din vechiul testament 'in ebraic'a, cum reprezint textul 'in calculator, 'in ce ordine? \item Literele se pot scrie adesea 'in felurite moduri; chiar l'as'ind la o parte informa'tia legat'a de font, dimensiune 'si orientare. 'In arab'a unele litere se scriu diferit 'in func'tie de vecinii lor; \item Voi reprezenta 'a ca dou'a semne (a 'si c'aciula) --- din care c'aciula este un semn care ``nu ocup'a spa'tiu'', deci se scrie peste cel anterior --- sau ca o singur'a liter'a? \item Reprezint ``A'' 'si ``a'' ca pe o aceea'si liter'a, 'intr-un caz modificat'a (m'arit'a), sau ca pe dou'a litere deosebite? \item 'In anumite limbi un semn se comport'a ca mai multe litere ('in german'a \ss\ se sorteaz'a ca 'si cum s-ar scrie ``ss''), dar se scrie ca una singur'a. 'In alte limbi e invers: 'in Spaniol'a ``ll'' este considerat'a o singur'a liter'a la sortare. Algoritmii de sortare devin deci mult mai complica'ti, pentru c'a nu mai pot face simple compara'tii liter'a cu liter'a (o simpl'a sortare lexicografic'a). \item 'In limba chinez'a literele nu sunt ordonate alfabetic, ci dup'a num'arul de liniu'te cu care se deseneaz'a. \item Informa'tii ca: sf'ir'situl de paragraf, de pagin'a, indentarea, num'arul de spa'tii albe sunt sau nu reprezentabile prin caractere (cum sunt de exemplu 'in setul ASCII ``New-Line'' sau ``Tab'')? \item C'ind scriu programe 'in C, cum reprezint caractere interna'tionale pentru mesaje date utilizatorului? \item Cum pot crea un fi'sier cu nume 'in Swahili? \item Cum se scrie o expresie regulat'a 'in Kanji? \end{itemize} Oricare din aceste probleme poate fi rezolvat'a, dar p'in'a c'ind nu toat'a lumea le va rezolva pe toate 'in acela'si fel (prin intermediul unui standard), programele risc'a s'a manipuleze obiecte pe care nu le mai 'in'telege nimeni 'in afar'a de autori. Probabil c'a 'inving'ator 'in lupta standardelor va ie'si p'in'a la urm'a Unicode, datorit'a suportului unor firme extrem de mari, 'si datorit'a calit'a'tilor sale tehnice. Standardul este descris 'in 8 cm\footnote{grosime.} de h'irtie la ora actual'a, 'si mai cre'ste. Sistemul de operare Windows NT de la Microsoft este construit integral cu Unicode 'in interior; totul, de la nume de fi'siere la mesaje de eroare este construit pe 16 bi'ti. Biblioteci speciale transform'a datele manipulate de programele ``vechi'' (care lucreaz'a cu caractere pe 8 bi'ti) 'in Unicode 'inainte de a ruga driverele din nucleu s'a le afi'seze. Chiar faptul ca Windows NT domin'a pia'ta sistemelor de operare la ora actual'a este un motiv major pentru ca Unicode s'a 'inving'a. \subsubsection{Reprezentarea diacriticelor} 'Inchei aici digresiunea mea despre standarde 'si reprezentarea caracterelor interna'tionale, 'si revin la pachetul meu mult mai modest, care 'incearc'a s'a rezolve unele dintre problemele limbii rom"ane. Hot'ar'irea mea final'a a fost s'a reprezint absolut tot textul folosind semne ASCII, lucru care o s'a m'a scuteasc'a de o sumedenie de probleme de portabilitate, pentru c'a virtual toate terminalele din lume recunosc setul de caractere ASCII. 'In schimb mi-am propus s'a folosesc o conven'tie care s'a aib'a urm'atoarele propriet'a'ti: \begin{itemize} \item S'a foloseasc'a semnele ASCII 'intr-un mod ne-ambiguu (de exemplu dac'a a's fi folosit semnul {\tt a+} pentru 'a, a's fi avut mari dificult'a'ti 'in a distinge formulele matematice de texte cu diacritice; conven'tia pe care am aleas-o 'in final nu e perfect ne-ambigu'a, dar e tolerabil de neambigu'a, cred; \item Ca o consecin't'a a ne-ambiguit'a'tii, ar trebui s'a fie foarte u'sor de scris un program care s'a converteasc'a un text scris cu diacritice folosind conven'tia mea, 'in orice alt'a conven'tie de reprezentare. Practic dac'a fac un {\em search-and-replace} pe un text pot ob'tine orice alt'a conven'tie. Par-examplu, dac'a dvs. folosi'ti pentru 'a semnele /a, 'si eu folosesc \{a\}, atunci 'inlocuind uniform \{a\} cu /a convertesc un text din reprezentarea mea 'in a dumneavoastr'a. \item Semnele pe care le folosesc s'a fie u'sor de tastat. 'In limba rom"an'a exist'a o sumedenie de cuvinte cu semne diacritice, deci m'ina mea va trebui s'a nu se deplaseze prea mult pe tastatur'a pentru a scrie semnele 'inso'titoare; de preferabil s'a nu folosesc SHIFT sau ceva 'inrudit. \item Metoda s'a se 'impace bine cu alte programe care manipuleaz'a texte. De exemplu eu scriu texte folosind editorul Emacs (vede'ti 'si articolul meu din PC-Report pe Mai 1997, aflat 'si la \verb|http://www.cs.cmu.edu/~mihaib/articles|), iar 'in Emacs tasta {\tt M-f} se deplaseaz'a peste un cuv'int. A's fi vrut ca semnele diacritice pe care le folosesc s'a nu fie considerate de Emacs ca fiind 'inafara cuvintelor. \end{itemize} P'in'a la urm'a alegerea s-a oprit asupra semnului apostrof: ' . De aceea voi scrie acum literele astfel:\end{romana} \verb|'a 'i 's 't| \begin{romana} pentru 'a, 'i, 's, 't. Probabil c'a alegerea pentru "a a fost mai pu'tin fericit'a: am ales \end{romana}\verb|"a|\begin{romana}. Dar s'a revenim la fi'sierele de configurare pentru {\tt ispell}\footnote{Ca dovad'a c'a principiile enumerate mai sus au fost bune, ini'tial alesem semnul $\backslash$ pentru diacritic; schimbarea la apostrof a fost 'ins'a foarte simpl'a, 'si a fost cauzat'a de dorin'ta de a inter-opera cu \LaTeX pentru care semnul $\backslash$ are o semnifica'tie special'a.}. Odat'a ce am hot'ar'it ce litere voi folosi, am purces la a scrie un fi'sier de configurare pentru {\tt ispell}. Formatul fi'sierului este documentat 'in paginile de manual ale programului {\tt ispell}. Acesta este con'tinutul fi'sierului {\tt rom.signs.aff}: fi'sierul de afixe pentru limba rom"an'a cu semne diacritice (cel pentru configura'tia f'ar'a diacritice este mai simplu). \end{romana} \begin{verbatim} nroffchars ().\\* texchars ()\[]{}<\>\\$*.% stringchar "'a" "'A" stringchar "'i" "'I" stringchar "'s" "'S" stringchar "'t" "'T" stringchar "\"a" "\"A" wordchars [a-z] [A-Z] \end{verbatim} \begin{romana} Folosind un limbaj foarte simplu 'ii descriu lui {\tt ispell} care caractere au semne speciale 'in fi'sierele scrise pentru {\tt nroff} 'si \TeX\ (acestea sunt dou'a programe foarte r'asp'indite 'in lumea Unix pentru tehnoredactarea de texte, care au folosesc ni'ste limbaje speciale pentru a descrie aranjarea 'in pagin'a a textului. Practic eu trebuie s'a 'ii spun lui {\tt ispell} c'a atunci c'ind manipulez un text scris pentru {\tt nroff}, respectiv \TeX, trebuie s'a ignore cuvintele care descriu aranjarea 'in pagin'a, 'si s'a corecteze numai restul textului.) Apoi 'ii indic lui {\tt ispell} c'a voi interpreta perechile de semne apostrof-a, apostrof-A, etc. drept o singur'a liter'a 'in textele mele. Asta este foarte important pentru c'a 'ii spune lui {\tt ispell} c'a ``f'i's'' este ob'tinut din ``f's'i'' prin schimbarea a dou'a litere (deci este ``aproape''), 'si nu prin permutarea unui 'sir de 4 caractere (cuvintele se vor scrie cu conven'tia mea astfel: \end{romana}\verb|f'i's f's'i|). \begin{romana} 'In fine, indic faptul c'a semnele ASCII obi'snuite pentru litere sunt componente ale cuvintelor. {\tt ispell} permite reguli 'si mai rafinate, pentru a indica de pild'a c'a anumite caractere sunt considerate litere numai dac'a apar 'in interiorul unui cuv'int (cum ar fi de pild'a liniu'ta de unire --), sau pentru a indica faptul c'a {\tt nroff} sau \TeX\ denot'a altfel un acela'si caracter. Observa'ti c'it de flexibil este {\tt ispell}: comportarea programului este influen'tat'a de o gr'amad'a de parametri dinafar'a, din fi'sierul de configurare. Aceasta este separarea de politic'a 'si mecanism de care vorbeam, care 'ii permite lui {\tt ispell} s'a fie simultan folosit 'in condi'tii at'it de diferite. \subsection{Dic'tionarele} A doua problem'a spinoas'a era: de unde dic'tionare? La aceast'a 'intrebare am r'aspuns imediat. \subsubsection{Achizi'tia de date} {\tt ispell} este un program interactiv, care este suficient de 'in'telept s'a fie de acord c'a nu 'stie totul. De fiecare dat'a c'ind {\tt ispell} g'ase'ste un cuv'int necunoscut, pe l'ing'a faptul c'a 'imi ofer'a o list'a de posibile corecturi, 'imi ofer'a posibilitatea de a introduce cuv'intul 'in dic'tionar. Exact pe asta m-am bazat 'si eu: voi construi dic'tionarul incremental, rul'ind {\tt ispell} pe texte (c'it se poate de) corecte. Dup'a o faz'a plictisitoare 'in care m'a va 'intreba mai toate cuvintele, va 'inv'a'ta vocabularul meu de baz'a 'si va deveni eficace. Construc'tia dic'tionarelor este 'in plin'a desf'a'surare, de'si ambele (cel cu diacritice 'si cel f'ar'a) au c'ite 40 de mii de cuvinte la ora actual'a. Principala mea surs'a de vocabular este edi'tia pe Internet a ziarelor ``Rom"ania Literar'a'' 'si ``Dilema'', plus, mai pu'tin, textele pe care le scriu eu 'insumi. \subsubsection{Analiza statistic'a} Dup'a ce am str'ins c'iteva mii de cuvinte, am folosit celelalte programe din pachetul cu care vine {\tt ispell} pentru a face o analiz'a statistic'a a dic'tionarelor. Analiza este util'a pentru c'a 'in fi'sierele de configurare 'ii pot descrie lui {\tt ispell} simple reguli de derivare cu prefixe 'si sufixe, pe care apoi el le folose'ste pentru a reduce m'arimea dic'tionarelor, memor'ind o singur'a dat'a r'ad'acinile comune. Pachetul care con'tine programul {\tt ispell} ofer'a pentru acest scop programele {\tt findaffix}, care analizeaz'a exhaustiv un dic'tionar, gener'ind informa'tii despre poten'tialele deriv'ari, 'si {\tt tryaffix}, care evalueaz'a economia care se poate ob'tine folosind un anumit affix. \subsubsection{Compresia prin prefixe 'si sufixe} Cum se folosesc afixele pentru a reduce m'arimea dic'tionarului? Pentru fiecare afix se define'ste (manual) c'ite o prescurtare de o liter'a. De exemplu, pentru prefixul ``re-'' am alocat litera E. Atunci, 'in loc ca 'in dic'tionar s'a apar'a cuvintele ``educare'' 'si ``reeducare, va ap'area doar o 'inregistrare de forma ``educare/E''. Practic am 'inlocuit un cuv'int 'intreg cu dou'a litere (/ 'si E). Pachetul {\tt ispell} vine 'impreun'a cu un alt program numit {\tt munchlist}, care, d'indu-i-se un dic'tionar 'si o list'a de afixe, comprim'a dic'tionarul la o reprezentare minim'a. Rezultatul este foarte eficace; chiar cu fi'sierele relativ primitive de afixe pe care le-am f'acut am reu'sit s'a reduc m'arimea dic'tionarelor la aproximativ 50-55\%. Restul fi'sierelor de configurare a afixelor este ocupat cu regulile prin care afixele se ata'seaz'a cuvintelor. {\tt ispell} 'stie s'a opereze mici modific'ari asupra r'ad'acinilor; asta cre'ste enorm utilitatea afixelor. Iat'a un fragment tipic dintr-o descriere a unui ``flag'' din {\tt rom.signs.aff}: \end{romana} \begin{verbatim} suffixes flag *I: U > LUI # bou > boului [^UA] > ULUI # porc > porcului [GC] A > -A,II # vaca > vacii [^CG] A > -A,EI # baba > babei \end{verbatim} \begin{romana} Traducere: indicatorul I va func'tiona 'in 4 feluri, depinz'ind de forma r'ad'acinii cuv'intului la care se aplic'a: \begin{enumerate} \item Dac'a r'ad'acina se termin'a 'in ``U'', atunci indicatorul I va cauza concatenarea 'sirului ``lui''. De exemplu, 'in dic'tionar cuv'intul ``bou/I'' va genera simultan ``bou'' 'si ``boului''; \item Dac'a r'ad'acina {\em nu} (nega'tia este indicat'a de semnul \verb|^|) se termin'a 'in ``U'' sau ``A'', atunci adaug 'sirul ``ului''; \item Dac'a r'ad'acina se termin'a 'in ``ga'' sau ``ca'', atunci regula va 'sterge ``A''-ul de la coad'a 'si va concatena un ``ii''; \item 'In fine, dac'a r'ad'acina se termin'a 'in ``a'', dar nu 'in ``ca'' sau ``ga'', atunci 'sterg ``A''-ul 'si adaug ``ei''. \end{enumerate} Observa'ti c'a aceste reguli nu sunt folosite pentru a {\em genera} noi cuvinte din cele existente, ci doar pentru a comprima un set de cuvinte dat, deci nu pot gre'si dac'a avem de-a face cu o excep'tie (de exemplu cuv'intul ``poarta'', care dup'a regulile de mai sus ar deveni ``poartei''). Singura consecin't'a este c'a ambele cuvinte vor ap'area 'in dic'tionar, pentru c'a nu se poate aplica compresia (voi avea 'si ``poarta'' 'si ``por'tii'' 'in dic'tionar). \subsection{Interfa'ta cu emacs} {\tt ispell} este prin construc'tie un program interactiv: analizeaz'a textul, 'si la prima eroare scrie pe ecran por'tiunea de text suspicioas'a, indic'ind posibile corecturi, 'si a'stept'ind ca utilizatorul s'a ia m'asuri. Dl. Kuenning 'ins'a a fost suficient de 'in'telept pentru a 'inzestra {\tt ispell} cu un mod de func'tionare ``batch'': ne-interactiv. Dac'a {\tt ispell} este pornit cu modificatorul {\tt -a} atunci nu mai scrie nimic pe ecran 'si nu mai cite'ste tastatura, ci scrie 'si cite'ste de la intrarea 'si ie'sirea sa standard. Practic de la intrare {\tt ispell} cite'ste un cuv'int, iar la ie'sire trimite 'siruri de caractere care descriu p'arerea lui despre acel cuv'int (dac'a e corect, dac'a nu ce variante sunt, etc). De exemplu, (de data asta 'in englez'a): \begin{verbatim} $ echo helo | ispell -a @(#) International Ispell Version 3.1.20 10/10/95 & helo 9 0: halo, held, hell, hello, helm, help, hero, he lo, he-lo $ \end{verbatim} Conven'tiile prin care {\tt ispell} r'aspunde sunt u'sor complicate; pe scurt, 'in linia de mai sus a spus c'a nu crede c'a acel cuv'int e corect, (prin semnul \&), 'si a indicat apoi 9 posibilit'a'ti corecte, separate prin virgule. Aceasta este o alt'a instan't'a a faimoasei separa'tii dintre politic'a 'si mecanism: mecanismul de corectare nu implementeaz'a 'si politica de interac'tiune. Asta permite interfa'tarea altor programe cu {\tt ispell}. De exemplu editorul de texte Emacs 'stie s'a converseze cu {\tt ispell}, bag'indu-i pe g'it (intrarea standard) cuvintele dintr-un buffer unul c'ite unul. 'In func'tie de r'aspuns discut'a el 'insu'si cu utilizatorul, pentru a 'inlocui cuvintele gre'site. \subsection{Fi'sierul de stil pentru \LaTeX} Pentru c'a 'imi tehnoredactez fi'sierele 'in \LaTeX, era natural s'a caut o metod'a de a folosi conven'tia de scriere cu apostroafe direct 'in \LaTeX. Nu a fost prea dificil, pentru c'a am dat peste un fi'sier de stil construit de Alexandru 'si Dan Corlan pe care mi l-am 'insu'sit, 'si 'in care am operat ni'ste minuscule modific'ari. Fi'sierul pune la-ndem'in'a un nou ``environment'', numit {\tt romana}, 'in interiorul c'aruia semnul apostrof 'si respectiv ghilimelele produc diacritice. Practic pot scrie acum texte astfel: \end{romana} \begin{figure}[h] \begin{center} \begin{tabular}{p{6.3cm}|p{2cm}|p{6.3cm}} \begin{minipage}{6.1cm} \begin{verbatim} \documentstyle[romana-]{article} \begin{document} 'In aceast'a parte apostroful nu are nici o influen't'a. \begin{romana} Dar 'in aceast'a parte se transform'a 'in diacritice. \end{romana} \end{document} \end{verbatim} \end{minipage} & \begin{romana} 'si voi genera urm'atorul document: \end{romana} & \begin{minipage}{6.1cm} 'In aceast'a parte apostroful nu are nici o influen't'a. \begin{romana} Dar 'in aceast'a parte se transform'a 'in diacritice. \end{romana} \end{minipage} \end{tabular} \end{center} \end{figure} \begin{romana} Fi'sierul de stil ar putea beneficia de mici 'imbun'at'a'tiri, pentru c'a anumite combina'tii se comport'a ciudat (de exemplu nu se mai pot scrie acolade dup'a ghilimele), dar este mai adesea util dec'it d'aun'ator. \subsection{Interfa'ta corectorului de limba rom"an'a cu utilizatorul} \subsubsection{Instalare} Pentru a putea folosi {\tt corect}, trebuie 'int'ii sa ave'ti pachetul cu {\tt ispell}. Necesare sunt fi'sierele {\tt buildhash} 'si {\tt ispell}; de celelalte v'a pute'ti lipsi. Dac'a ave'ti un sistem Unix, le pute'ti lua de la {\tt ftp://prep.ai.mit.edu/pub/gnu}. Pagina lui {\tt ispell} este la {\tt http://fmg-www.cs.ucla.edu/fmg-members/geoff/ispell.html}; acolo mai pute'ti afla o gr'amad'a de lucruri utile despre acest program. Cel care instaleaz'a pachetul de fi'siere are o misiune relativ simpl'a: trebuie s'a decid'a locul unde fi'sierele se vor plasa 'si cum ajung utilizatorii la ele. Exist'a dou'a variante de baz'a: \begin{enumerate} \item Instalarea este f'acut'a pentru 'intregul sistem (de administrator, 'in a'sa fel 'inc'it to'ti utilizatorii s'a poat'a beneficia); \item Un utilizator f'ar'a privilegii 'i'si instaleaz'a pachetul pentru uzul personal 'in contul lui. \end{enumerate} Cel care instaleaz'a va trebui s'a citeasc'a {\tt Makefile}-ul 'si s'a modifice c'iteva variabile. Valorile care ar fi interesante sunt {\tt ROMSPELLBASE} 'si {\tt LATEXDIR}, 'si indic'a unde se vor plasa dic'tionarele, respectiv fi'sierul de stil pentru \LaTeX. Pentru ca utilizatorii s'a poat'a accesa fi'sierul de stil, el trebuie s'a fie 'intr-un loc 'in care \LaTeX s'a-l poat'a c'auta. Administratorul 'il poate pune acolo unde sistemul local are toate celelalte fi'siere de stil. Un utilizator obi'snuit 'il poate pune oriunde, 'si apoi poate indica lui \LaTeX acel loc folosind variabila {\tt TEXINPUT}. De exemplu, eu mi-am pus fi'sierul {\tt romana-.sty} 'in {\tt \$HOME/data/tex} 'si am pus variabila astfel: \end{romana} \begin{verbatim} export TEXINPUTS=".:$HOME/data/tex:" \end{verbatim} \begin{romana} 'In plus, pentru ca Emacs s'a poat'a invoca {\tt ispell} pentru a corecta texte rom"ane'sti, fi'sierul {\tt for-emacs}, care este generat automat, ar trebui executat de Emacs-ul tuturor utilizatorilor care scriu 'in rom"an'a. Iar'a'si, exist'a dou'a variante: fiecare utilizator poate concatena acest fi'sier la propriul fi'sier de ini'tializare {\tt .emacs}, sau acest fi'sier poate fi pus de administrator 'intr-un fi'sier global de ini'tializare al lui Emacs (de exemplu {\tt site-start.el}). \subsubsection{Utilizare} Dup'a ce administratorul a f'acut treburile murdare de instalare, folosirea corectorului ar trebui s'a fie banal'a. Datorit'a unui mic script, tot ce trebuie f'acut pentru a corecta un text este de a tasta: \begin{verbatim} corect fisier-de-corectat \end{verbatim} Simplu ca bun'a ziua! (Dac'a fi'sierul este scris 'in rom"an'a cu diacritice, tasta'ti {\tt corect -s fisier}.) Pentru a corecta din Emacs folosi'ti comenzile Emacs: \begin{verbatim} M-x ispell-change-dictionary \end{verbatim} La 'intrebarea care urmeaz'a, r'aspunde'ti {\tt romana}, respectiv {\tt rom-diacritice}, dup'a cum dori'ti. Apoi tasta'ti: \begin{verbatim} M-x ispell-buffer \end{verbatim} \end{romana} \end{document}