Alexm
Intră

Folosește-ți e-mailul sau numele de utilizator și parola pentru a te identifica

Înscrie-te

Vei primi un e-mail cu un link de activare. Ultimul câmp este opțional


🠉

Restaurarea punctuației cu PHP

Câteva soluții pe care le-am testat și aș dori să le împărtășesc cu cei care nu doresc sau nu pot folosi alte limbaje

Da, încă folosesc PHP. Da, încă e pe lista favoriților. Da, sunt bătrân 😁. Nu, nu este un limbaj mort. S-ar putea să nu fie cea mai bună alegere pentru ceea ce încerc să fac aici, dar uneori pur și simplu nu ai o alternativă sau poate vrei doar să dovedești că limbajele sunt doar instrumente și, dacă știi cum să le folosești, poți obține orice (cu compromisuri care pot fi acceptabile în anumite situații).

Verificarea ortografică și corectarea automată au devenit o parte indispensabilă a multor produse și servicii software, ajutând utilizatorii să scrie, oferind sugestii pe măsură ce tastează, arătând greșeli sau modalități mai bune de a exprima ceva. În ultimul timp, și mai ales odată cu progresul AI, un număr tot mai mare de aplicații au început, de asemenea, să ajute oamenii să folosească punctuația corectă. Este posibil să fi observat aceasta la instrumentele de birou și productivitate, aplicațiile de mesagerie text sau platforme sociale.

Am vrut să aprofundez un pic acest subiect, dar nu am găsit nimic pentru PHP; așa că am decis cel puțin să dau un start lucrurilor și să arunc o privire la câteva moduri prin care am putea verifica și restabili punctuația într-un mediu de dezvoltare bazat pe PHP, indiferent dacă se utilizează CLI sau doar se dorește implementarea acestei caracteristici pe partea de server a unei aplicații web - scenariul principal pe care l-am avut în minte în timpul cercetării mele.

Spre deosebire de verificarea ortografică - unde s-ar putea crea o funcție de bază care doar verifică un text făcând comparație cu o listă de termeni corecți și se asigură că totul este scris în conformitate - punctuația nu este atât de simplă, deoarece regulile sale sunt puțin mai complexe și, de asemenea, pot varia în funcție de contextul scrierii și de scriitor.

Folosim punctuația pentru două scopuri principale: logică (pentru a construi texte corecte din punct de vedere gramatical care pot fi parcurse și înțelese) și retorică (pentru a ajuta cititorul să se deplaseze printr-un text la un anumit ritm, pentru a transmite un sentiment sau o anume idee și pentru a ajuta la intonație). În timp ce prima parte poate fi rezolvată destul de elegant de algoritmi într-o oarecare măsură, a doua este în mare parte influențată de persoana care scrie, stilul și natura lucrării lor; identificarea acestora caracteristici cu precizie și fără ajutor suplimentar de la utilizator nu este o sarcină ușoară pentru un calculator digital.

Permite-mi să încep prin a da un exemplu de câteva propoziții, în primul rând lipsite de orice punctuație, apoi cu câteva semne de punctuație de bază pentru o logică mai bună și, în cele din urmă, textul scris de cineva care folosește punctuația pe larg pentru a îmbunătăți aspectul retoric al textului.

Fără semne de punctuație
Am mers la magazin astăzi A fost o călătorie lungă și plictisitoare Și am cumpărat câteva lucruri ouă pâine și brânză Minunat
L-am văzut și pe prietenul meu Ioan acolo căuta un cadou pentru ziua de naștere a surorii lui
Punctuație de bază
Am mers la magazin astăzi . A fost o călătorie lungă și plictisitoare. Și am cumpărat câteva lucruri: ouă, pâine și brânză. Minunat!
L-am văzut și pe prietenul meu Ioan acolo. Căuta un cadou pentru ziua de naștere a surorii lui.
Punctuație îmbogățită
Am mers la magazin astăzi - a fost o călătorie lungă și plictisitoare - și am cumpărat câteva lucruri: ouă, pâine și brânză. Minunat!
L-am văzut și pe prietenul meu Ioan acolo; căuta un cadou pentru ziua de naștere a surorii lui.

După cum se vede, pe lângă cele care nu lasă loc de îndoială (de obicei, virgulele și punctele sunt cele mai ușor de plasat), multe dintre acestea depind de factorii prezentați anterior (cum ar fi liniuța sau punctul și virgula). Prin urmare, putem încerca să ajungem la cel mai bun compromis între logică și retorică (o opțiune adecvată în contexte informale), dar putem și oferi utilizatorului și opțiuni pentru a ghida procesul de restaurare.

Să păstrăm aceste exemple aici pentru referințe ulterioare și să vedem care sunt cursurile posibile pe care le-ar putea lua cineva atunci când se angajează într-un astfel de efort. Inițial, am vrut să adaug cod în această postare, dar mi-am dat seama că o va face prea lungă și dezordonată, fără să adauge mult. În orice caz, am decis să încep și un proiect care implementează soluțiile propuse aici și voi adăuga un link către repozitoriu la sfârșitul acestei pagini, pentru cei interesați de ceva mai mult decât explicații.

Soluția 1: doar PHP

Probabil cel mai minuțios mod de a face așa ceva este folosind doar PHP pur. Nu vreau să spun că ar fi greu, dar e ca și cum ai construi unul din acele computere mecanice vechi. O mulțime de rotițe de modificat și ajustat pentru a-l face să funcționeze. Avantajul este că nu veți avea nevoie de nimic altceva decât de acest cod pentru a-l rula oriunde (CLI, site web, aplicație web). În această primă provocare, cel mai important pas este stabilirea unor reguli clare pentru fiecare dintre semnele de punctuație: când și cum trebuiesc aplicate.

Nu sunt eu un geniu al gramaticii (deși am fost destul de bun la asta în școală), dar dacă ar fi să începem cu punctul, o regulă evidentă este că majoritatea propozițiilor se termină cu una. Acum - și ignorând excepțiile pentru moment - știm că o propoziție ar trebui să aibă cel puțin un subiect și un predicat pentru a avea sens; ceea ce înseamnă că trebuie să identificăm părțile textului dat. De fapt, aceasta va fi o primă acțiune esențială atunci când se plasează corect orice semn de punctuație într-o propoziție.

Etichetarea cuvintelor

Prin urmare, prima componentă a scriptului nostru de restaurare ar trebui să fie ceea ce se numește un etichetator de PAV (părți ale vorbiri): o funcție care identifică fiecare cuvânt dintr-o propoziție și returnează rolul său cel mai probabil. O modalitate simplă de a realiza acest lucru va fi crearea unui dicționar. Acesta ar putea exista ca un tabel într-o bază de date, ca fișier de date folosind formate precum XML sau JSON, sau am putea folosi pur și simplu o matrice. Ceva de genul:

  
$text = "Am mers la magazin astăzi A fost o călătorie lungă și plictisitoare Și am cumpărat câteva lucruri ouă pâine și brânză Minunat";

$dictionar = [
    "am"        => "verb",       "mers"   => "verb",        "la"      => "prepozitie", "magazin"       => "substantiv",
    "astazi"  => "adverb",       "a"      => "verb",        "fost"    => "verb",       "o"             => "articol",
    "calatorie" => "substantiv", "lungă"  => "adjectiv",    "și"      => "conjunctie", "plictisitoare" => "adjectiv",
    "cumpărat"  => "verb",       "câteva" => "determinant", "lucruri" => "substantiv", "ouă"           => "substantiv",
    "pâine"     => "substantiv", "brânză" => "substantiv",  "minunat" => "adjectiv"
];
  

Totuși, asta nu va funcționa atunci când se acoperă o întreagă limbă. Matricea ar fi prea mare și nepractică. O bază de date ar face o treabă mai bună, mai ales dacă este activată și memorarea în cache. Alternativ, s-ar putea folosi un API care să ofere astfel de informații și chiar mai mult. Se pot chiar combina ambele surse (se utilizează API-ul atunci când cuvântul nu este găsit în baza de date). Pe dexonline.ro este foarte simplă accesarea definițiilor în format JSON atașând /json la sfârșitul solicitării. Mai apoi trebuie extrasă clasa cuvântului. Dicționarul în limba română se poate descărca și de aici apoi se poate importa într-o bază de date folosind un script.

În ultimă instanță, am putea încerca, de asemenea, să ghicim ce parte a vorbirii ar putea fi un cuvânt bazându-ne pe șabloane generale pe care uneori le împărtășesc cuvintele din aceeași clasă. De exemplu, cuvintele care se termină în "ând" sunt de obicei verbe (modul gerunziu).

Extragerea propozițiilor

Cu excepția cazului în care vizăm un scenariu foarte specific și dacă dorim să creăm o soluție care să poată restabili orice text dat, cele mai nefavorabile cazuri trebuie luate în considerare. Cel mai rău: nu există deloc punctuație în text. Extragerea propozițiilor din astfel de texte este o oarecare provocare. Să ne întoarcem la exemplele noastre și să vedem un motiv:

Am mers la magazin astăzi A fost o călătorie lungă și plictisitoare Și am cumpărat câteva lucruri ouă pâine și brânză Minunat
Unde se termină o propoziție și unde începe cealaltă? Dacă ne uităm cu atenție, vedem că există mai multe rezultate posibile:
Am mers la magazin astăzi. A fost o călătorie lungă și plictisitoare. Și am cumpărat câteva lucruri ...
Am mers la magazin. Astăzi a fost o călătorie lungă și plictisitoare. Și am cumpărat câteva lucruri ...
Am mers la magazin. Astăzi a fost o călătorie lungă și plictisitoare și am cumpărat câteva lucruri ...

Pentru a rezolva misterul, feedback-ul utilizatorilor ar putea fi solicitat în acest moment. În mod explicit, folosind casete de dialog, ferestre pop-up sau elemente mai puțin intruzive, cum ar fi indicii sau semne; sau doar prin furnizarea de setări care pot fi ajustate în funcție de preferințele fiecăruia. De exemplu, ar putea exista o opțiune care interzice propozițiile care încep cu o conjuncție (cum ar fi "și") sau cu un adverb (cum ar fi "astăzi").

În cele din urmă, ar trebui să existe un mod implicit de interpretare pentru cei care doresc doar o restaurare rapidă și nu sunt prea preocupați de toate acestea; apoi, un mod avansat pentru ca utilizatorii să poată ajusta toate setările până când obțin exact ceea ce doresc.

După numeroase încercări și erori, am reușit să creez următoarea diagramă inițială pentru algoritmul care va extrage propoziții dintr-un text:

  1. Obține rolul cuvântului pe baza dicționarului și a relației sale cu cuvintele înconjurătoare
  2. Inserează o propoziție nouă într-o matrice, dacă niciuna nu a fost deja creată
  3. Dacă există posibilitatea ca cuvântul să aparțină unei alte propoziții decât cea curentă, adaugă noua propoziție în matrice
  4. Atribuie o valore de pondere cuvântului pentru fiecare propoziție existentă căreia i-ar putea aparține
  5. Mărește sau micșorează aceste valori pe baza cuvintelor înconjurătoare sau a unor factori precum setările utilizatorului
  6. În cele din urmă, plasează cuvintele în propozițiile pentru care au cele mai mari ponderi și returnează rezultatul

Unii dintre acești pași sunt destul de ușor de implementat, alții vor avea nevoie de mai multă răbdare (va trebui să testăm multe scenarii de caz - testarea unitară ar putea fi foarte utilă în această etapă). Dar cred că această schemă este suficient de solidă pentru a servi atât pentru extragerea propozițiilor, cât chiar și pentru găsirea locului oricărui alt semn de punctuație. Este un bun punct de start.

Modificatori

Am menționat că rolul și ponderea unui cuvânt pot fi modificate prin prezența altor cuvinte. Cuvântul "magazin" este un substantiv în sine, dar când avem prepoziția "la" în față, acest cuvânt devine parte a unui complement circumstanțial de loc, ceea ce crește probabilitatea ca toate să aparțină aceleiași propoziții.

Pentru a lua în considerare toate aceste combinații complexe, putem defini modificatori pentru ca algoritmul să genereze ipoteze mai precise cu privire la proprietățile unui cuvânt. De exemplu, "la" vine cu un modificator care va crește proprietatea pondere a următorului substantiv, ceea ce înseamnă că există o probabilitate mai mare ca aceste două cuvinte să aparțină împreună aceleiași propoziții. Modificatorul poate de asemenea transforma substantivul în obiectul aceleași prepoziții, ceea ce poate fi util pentru a afla alte semne de punctuație.

Vor exista câțiva modificatori generali pentru cele mai frecvente situații (cum ar fi un articol nehotărât, care aproape întotdeauna este urmat de un substantiv) și apoi vor exista modificatori specifici care vizează anumite cuvinte sau grupuri de cuvinte. Comportamentul modificatorilor generali ar putea fi codificat direct (cu excepția cazului în care dorim suport pentru mai multe limbi) sau definit ca o listă separată de structuri care sunt analizate și interpretate de algoritm la nivel global. Modificatorii specifici pot fi definiți în interiorul dicționarului, cu cuvintele de care sunt strâns legați.

Un ultim lucru la care trebuie să ne gândim este abstractizarea unor astfel de modificatori. Aceștia vor fi cel mai probabil stocați sub forma unei structuri (poate în format JSON), care conține mai multe perechi de elemente cheie-valoare ce specifică cuvintele sau clasele care sunt afectate de modificator, relația și intervalul / distanța dintre cuvinte, valoarea ponderii și, dacă modificatorul schimbă rolul unui cuvânt, clasa nouă a acestuia. Această structură se va cristaliza pe măsură ce începem să construim dicționarul și să testăm codul. Pe lângă asta, ea va permite colaborarea unui lingvist, care poate lucra la îmbunătățirea părții gramaticale a proiectului fără să aibă nevoie de cunoștințe tehnice avansate sau să modifice codul.

Doar pentru a exemplifica, structura unui modificator ar putea arăta astfel atunci când este stabilită ca o matrice PHP:
  
"la" => [ [ "+[0..2]substantiv" ] => [ "pondere" => .8, "rol" => "adverb" ] ]
  
În primul rând, cuvântul care vine cu modificatorul, tipul de cuvinte pe care le modifică (orice substantiv care urmează la o distanță de maximum 2 cuvinte, apoi ponnderea adăugată cuvintelor afectate și, în final, noul rol atribuit acestora).

Semne de punctuație

Propozițiile se pot termina cu alte semne de punctuație, nu doar cu punct. Putem adăuga pur și simplu punctuația finală a unei propoziții la matricea conținând-ui cuvintele pe care am menționat-o mai devreme. Propoziția va fi apoi construită prin unirea tuturor elementelor, inclusiv a semnelor de punctuație.

  
$propozitii = [
    [ "L", "am", "văzut", "și", "pe", "prietenul", "meu", "Ioan", "acolo", "." ],
    [ "Căuta", "un", "cadou", "pentru", "ziua", "de", "naștere", "a", "surorii", "lui", "." ]
];
  

Acum că am schițat o posibilă abordare a extragerii propozițiilor și a punctuației lor finale, vom trece la celelalte semne de punctuație. Locul lor într-o propoziție poate fi calculat într-un mod similar: folosind atât modificatori generali cât și specifici. De exemplu, o enumerare de substantive adaugă o virgulă între fiecare dintre ele. Acesta este un modificator general. Cuvântul "lucruri", urmat de o enumerare de substantive este urmat de două puncte, înaintea enumerării. Acesta este un modificator specific care vine exact cu acest cuvânt. Din nou, utilizatorilor li se pot furniza setări diferite pentru a controla cazurile speciale și pentru a ajusta comportamentul algoritmului în funcție de nevoile lor.

Un ultim lucru de reținut este dacă textul de analizat are deja anumite semne de punctuație în el sau nu. Aici, am putea fie să-l curățim complet și să avem încredere deplină în algoritmul nostru, fie să profităm de punctuația existentă pentru a accelera procesul. De exemplu, punctele existente ar ajuta la extragerea mai rapidă a propozițiilor pentru a trece la etapele următoare. Utilizatorul ar trebui, din nou, să aibă opțiunea de a alege modul în care trebuie tratată punctuația existentă.

... va continua