Egen stavningskontroll. Hur hålla koll på ord och positioner?

Permalänk
Medlem

Egen stavningskontroll. Hur hålla koll på ord och positioner?

Håller på med ett projekt där jag ska göra en egen "stavningskontroll" som ska arbeta på en textsträng. Kontrollen görs hela tiden och bör därför vara skapligt effektiv.

Jag har googlat en del men hittar bara beskrivningar av hur själva kontrollen görs. Det jag vill veta är hur man på ett smart sätt håller koll på alla ord (fel och rättstavade) i strängen och deras positioner. Detta måste finnas undanlagrat då vissa rättningar ska ske automatiskt när man skriver.

Att spara varje nytt ord tillsammans med ett index är en simpel lösning, men problem uppstår då man börjar göra manipulationer mitt i strängen. Att förskjuta alla efterföljande index känns inte optimalt. En länkad lista som bara håller koll på orden och avståndet till nästa element löser det problemet, men måste då traverseras från början varje gång.

Hur sköts sådant här i normala fall (MS Office & liknande)? Vilka datastrukturer och algoritmer lämpar sig för den här typen av ändamål?

Permalänk
Medlem

Om du har tillgång till texteditorn vars text det är som påverkas så skulle jag göra följande:
Ge varje rad ett unikt id.
Alternativt, gör en checksumma av varje rad och jämför det mot befintliga rader. Raderna som du redan har är redan uträknade.

Att arbeta på radnivå gör så att du bara behöver kontrollera raderna som är påverkade (dirty).

Låter något av det jag har sagt rimligt/genomförbart?

Visa signatur

ηλί, ηλί, λαμά σαβαχθανί!?

Permalänk
Medlem
Skrivet av Leedow:

Om du har tillgång till texteditorn vars text det är som påverkas så skulle jag göra följande:
Ge varje rad ett unikt id.
Alternativt, gör en checksumma av varje rad och jämför det mot befintliga rader. Raderna som du redan har är redan uträknade.

Att arbeta på radnivå gör så att du bara behöver kontrollera raderna som är påverkade (dirty).

Låter något av det jag har sagt rimligt/genomförbart?

"Editorn" är ett textfält i en GWT-applikation. Det enda jag har att arbeta med är alltså en textsträng, så din idé (som dock lät väldigt bra) blir nog svår att genomföra =/

Det innebär också att ändringar inte skapar några events av något slag. Jag måste alltså manuellt kolla efter ändringar med jämna (1s för tillfället) mellanrum, men det är ett mindre problem

Permalänk
Medlem
Skrivet av MrMadMan:

"Editorn" är ett textfält i en GWT-applikation. Det enda jag har att arbeta med är alltså en textsträng, så din idé (som dock lät väldigt bra) blir nog svår att genomföra =/

Det innebär också att ändringar inte skapar några events av något slag. Jag måste alltså manuellt kolla efter ändringar med jämna (1s för tillfället) mellanrum, men det är ett mindre problem

Ok, men vad tror du på den alternativa lösningen då?

Alltså att göra en checksumma av varje rad. Jag tror du tjänar på det i längden eftersom att bara det nya/påverkade rader behövs kontrolleras. Checksumman blir alltså IDt. Det behöver inte vara unikt heller då flera rader kan (beroende på vilken text som skrivs) vara identiska.

Det här är ju bara ett av problemen som sagt. Att indexera/placera orden som är ok/inte ok har jag inte ens funderat på.

Vi kan sova på saken och hoppas på att någon annan har något intressant förslag.
Rolig nöt att försöka knäcka!

Visa signatur

ηλί, ηλί, λαμά σαβαχθανί!?

Permalänk
Rekordmedlem

Ingen aning om hur det ser ut i koden, men du kan väl plocka hem OO/libreoffice koden och ta en kik hur de löst det där, men det kanske är för mycket fusk

Visa signatur

Ryzen 5 2400G, Asus ROG STRIX B350-F Gaming, 500GB Samsung 970EVO NVMe M.2 och en väldig massa masslagring. Seasonic Focus+ Gold 650W, Antec P 180 med Schyte o Sharkoon fläktar via en t-balancer, Tittar på en Acer ET430Kbmiippx 43" 4K
Främre ljudkanalerna återges via Behringer DCX2496, högtalare Truth B3031A, Truth B2092A Har också Oscilloskop, mätmikrofon och en Colorimeter.

Permalänk
Medlem
Skrivet av Leedow:

Ok, men vad tror du på den alternativa lösningen då?

Alltså att göra en checksumma av varje rad. Jag tror du tjänar på det i längden eftersom att bara det nya/påverkade rader behövs kontrolleras. Checksumman blir alltså IDt. Det behöver inte vara unikt heller då flera rader kan (beroende på vilken text som skrivs) vara identiska.

Det här är ju bara ett av problemen som sagt. Att indexera/placera orden som är ok/inte ok har jag inte ens funderat på.

Vi kan sova på saken och hoppas på att någon annan har något intressant förslag.
Rolig nöt att försöka knäcka!

Jag tror du får förklara närmare hur du menar här...

Skrivet av mrqaffe:

Ingen aning om hur det ser ut i koden, men du kan väl plocka hem OO/libreoffice koden och ta en kik hur de löst det där, men det kanske är för mycket fusk

Fusk är det väl inte... Men frågan är om man skulle begripa något

Permalänk
Medlem

Kan du inte bara göra som flyspell-mode i emacs - alltså att testa ett ord precis efter man har skrivit klart det, dvs. när man trycker på mellanslag?

Permalänk
Medlem
Skrivet av MrMadMan:

Jag tror du får förklara närmare hur du menar här...

Det är svårt att förklara närmare... Jag försöker.

1. Skicka in texten till rättstavaren (kallas text1 nu)
2. Rättstavaren splittar text1 på nya rader.
3. Rättstavaren gör en checksumma av varje rad baserat på alla tecken på denna rad.
4a. Rättstavaren jämför radernas checksumma i text1 med checksummor från en befintlig texts rader (texten från innan denna rättstavning gjordes. Vi har alltså alltid OLD och NEW, exempelvis text0 och text1)
4b. Checksummor som skiljer sig är alltså nya eller påverkade rader.
5. Vid nya/påverkade rader så görs rättstavning för dessa raders ord.

Jag har inte alls testat detta. Jag tänker bara att det borde vara bättre att slå upp rättstavning för förändrade raders ord än att göra det för alla varje gång. Det kan ju visa sig att det kostar mer att göra på detta sätt. Det kanske till och med kostar mer än att jämföra raderna utan checksummor.

Visa signatur

ηλί, ηλί, λαμά σαβαχθανί!?

Permalänk
Medlem
Skrivet av Leedow:

Det är svårt att förklara närmare... Jag försöker.

1. Skicka in texten till rättstavaren (kallas text1 nu)
2. Rättstavaren splittar text1 på nya rader.
3. Rättstavaren gör en checksumma av varje rad baserat på alla tecken på denna rad.
4a. Rättstavaren jämför radernas checksumma i text1 med checksummor från en befintlig texts rader (texten från innan denna rättstavning gjordes. Vi har alltså alltid OLD och NEW, exempelvis text0 och text1)
4b. Checksummor som skiljer sig är alltså nya eller påverkade rader.
5. Vid nya/påverkade rader så görs rättstavning för dessa raders ord.

Jag har inte alls testat detta. Jag tänker bara att det borde vara bättre att slå upp rättstavning för förändrade raders ord än att göra det för alla varje gång. Det kan ju visa sig att det kostar mer att göra på detta sätt. Det kanske till och med kostar mer än att jämföra raderna utan checksummor.

Om jag inte missförstår något så måste man alltså kontinuerligt göra checksummor för alla rader i den nya texten och jämföra med samtliga checksummor i den gamla (eftersom vi arbetar med ett okänt antal oindexerade textrader). Om man ändå måste räkna ut checksums vid varje check så känns det rent intuitivt "billigare" att jämföra nytt-tecken mot gammalt-tecken.

edit: ok, jag tror jag förstår idén bättre nu. Det känns som att metoden borde fungera bra på korta rader och mindre bra om man skriver ett längre stycke utan radbrytningar, då hela raden måste bearbetas för att få ett checksum att jämföra med.

Visa signatur

Kom-pa-TI-bilitet

Permalänk
Medlem
Skrivet av Teknocide:

Om jag inte missförstår något så måste man alltså kontinuerligt göra checksummor för alla rader i den nya texten och jämföra med samtliga checksummor i den gamla (eftersom vi arbetar med ett okänt antal oindexerade textrader). Om man ändå måste räkna ut checksums vid varje check så känns det rent intuitivt "billigare" att jämföra nytt-tecken mot gammalt-tecken.

edit: ok, jag tror jag förstår idén bättre nu. Det känns som att metoden borde fungera bra på korta rader och mindre bra om man skriver ett längre stycke utan radbrytningar, då hela raden måste bearbetas för att få ett checksum att jämföra med.

Ja, det stämmer. Hade varit väldigt kul att jämföra det där. Varför jag tänker checksummor är för att det "gamla" resultatets checksumma redan är uträknat. Men visst, den nya raden måste göras till en checksumma. Jämförelsen newRow[x] == oldRow[y] är dyrare än checksum1[x] == checksum2[y]. Möjligtvis så kanske checksum-uträkningen är dyrare än den enkla jämförelsen. Jag kan inte komma på någon enkel checksumma som skulle vara tokbillig. Avgränsningar kan inte göras då bara ett tecken kan skilja sig.
För att optimera så tror jag ändå att man måste bryta ut det på radnivå för att slippa rättstavning på redan avklarade rader. Ännu bättre hade kanske varit att ha något på ord-nivå eller det också. Frågan är hur pass stor minnesanvändningen får vara...

Visa signatur

ηλί, ηλί, λαμά σαβαχθανί!?

Permalänk
Medlem
Skrivet av Leedow:

Ja, det stämmer. Hade varit väldigt kul att jämföra det där. Varför jag tänker checksummor är för att det "gamla" resultatets checksumma redan är uträknat. Men visst, den nya raden måste göras till en checksumma. Jämförelsen newRow[x] == oldRow[y] är dyrare än checksum1[x] == checksum2[y]. Möjligtvis så kanske checksum-uträkningen är dyrare än den enkla jämförelsen. Jag kan inte komma på någon enkel checksumma som skulle vara tokbillig. Avgränsningar kan inte göras då bara ett tecken kan skilja sig.
För att optimera så tror jag ändå att man måste bryta ut det på radnivå för att slippa rättstavning på redan avklarade rader. Ännu bättre hade kanske varit att ha något på ord-nivå eller det också. Frågan är hur pass stor minnesanvändningen får vara...

Approachen med checksummor kan omöjligt vara speciellt effektiv...
Strängen måste ju splittas, och checksummor beräknas för varje ändring som görs!

I det stora hela handlar det om att separera orden som specifika objekt, med referenser till deras position i texten, och referenser till stavningsförslag. Orden ska också markeras med en annan bakgrundsfärg när de är felstavade och det viktigt att kunna slå av/på denna markering för specifika instanser av ett ord.

Vad jag är ute efter är alltså något slags register, tabell, lista eller dylikt...

Permalänk
Medlem

Min ursprungliga tanke var att skapa en ordlista i form av ett btree med flera "entry points", en för varje bokstav.
En grundläggande definition kan exempelvis ha 29 entry points för bokstäverna a till och med ö. Dessa entry points fungerar som index in i trädet; man kan se dem som roten på flera "under-träd". Det går också att ha 29 separata btrees men tanken på en samlad datastruktur med smarta index känns mer rolig.

Hursomhelst, datastrukturen kombineras med en enkel klass som håller reda på varje ord i rutan. Kanske något i stil med

class CheckedWord { long startpos; String s; // faktiskt värde }

Dictionaryn kan i sin tur ha

String[] getSuggestionsFor(String s) { ... } // hämtar förslag för strängen s, praktiskt taget alla noder som börjar med strängen 's'. Använder första bokstaven i s som index för snabbare lookups

En vektor representerar alla positioner i texten. Ett index i vektorn kan antingen vara ett CheckedWord eller null. Är värdet null letar man sig framåt tills man hittar en CheckedWord, och sedan räknar man längden på CheckedWord.s och drar det ifrån vektorns index för att få startpositionen (dvs vektorn registrerar bara stället där ordet slutar för att undvika en referens för varje bokstav i ordet)

edit: exempel

text: Lorem ipsum dolor sit amet array: 0,0,0,0,CheckedWord (Lorem),0,0,0,0,0,0,CheckedWord (ipsum), osv

Hitta ord på position 8: array[8] = 0 (följt av 0, 0, CheckedWord (ipsum)). Gå framåt i arrayen tills vi hittar ett CheckedWord (position 11). Ta längden av ordet (ipsum = 5). Vi vet nu att ordet börjar på position 11-5 = 6. Gör en lookup på ordet 'ipsum' i dictionary, färga beroende på resultat, etc etc..

Visa signatur

Kom-pa-TI-bilitet

Permalänk
Medlem
Skrivet av Teknocide:

Min ursprungliga tanke var att skapa en ordlista i form av ett btree med flera "entry points", en för varje bokstav.
En grundläggande definition kan exempelvis ha 29 entry points för bokstäverna a till och med ö. Dessa entry points fungerar som index in i trädet; man kan se dem som roten på flera "under-träd". Det går också att ha 29 separata btrees men tanken på en samlad datastruktur med smarta index känns mer rolig.

Hursomhelst, datastrukturen kombineras med en enkel klass som håller reda på varje ord i rutan. Kanske något i stil med

class CheckedWord { long startpos; String s; // faktiskt värde }

Dictionaryn kan i sin tur ha

String[] getSuggestionsFor(String s) { ... } // hämtar förslag för strängen s, praktiskt taget alla noder som börjar med strängen 's'. Använder första bokstaven i s som index för snabbare lookups

En vektor representerar alla positioner i texten. Ett index i vektorn kan antingen vara ett CheckedWord eller null. Är värdet null letar man sig framåt tills man hittar en CheckedWord, och sedan räknar man längden på CheckedWord.s och drar det ifrån vektorns index för att få startpositionen (dvs vektorn registrerar bara stället där ordet slutar för att undvika en referens för varje bokstav i ordet)

edit: exempel

text: Lorem ipsum dolor sit amet array: 0,0,0,0,CheckedWord (Lorem),0,0,0,0,0,0,CheckedWord (ipsum), osv

Hitta ord på position 8: array[8] = 0 (följt av 0, 0, CheckedWord (ipsum)). Gå framåt i arrayen tills vi hittar ett CheckedWord (position 11). Ta längden av ordet (ipsum = 5). Vi vet nu att ordet börjar på position 11-5 = 6. Gör en lookup på ordet 'ipsum' i dictionary, färga beroende på resultat, etc etc..

Jag har funderat På exakt den här lösningen. Problemet som uppstår är förstås när man gör en modifikation på ett annat ställe än i slutet. Då måste alla efterföljande element förflyttas. Men det är ju inte speciellt dyra operationer vi talar om...
Jag ska eventuellt ge det ett försök!

Jag fick en smått galen idé att lägga in något slags kodsystem med koder som inte visas som text i dokumentet.

Vi kanske sätter <index> (och skyddar dessa så de inte får skrivas in) efter varje inskrivet ord:

text: Lorem ipsum dolor sit amet kodat: Lorem<1> ipsum<2> dolor<3> sit<4> amet<5>

Dessa koder kan då lagras som nycklar i en Hashtabell där ord-objekten blir värden.

Man slipper då problem med index... Men frågan är om det är genomförbart? Jag kodar i Java och använder för tillfället SWT för GUI.

Permalänk
Medlem

Jag hängde inte med på vad indexet skulle användas till tror jag.
Du har naturligtvis rätt i att det blir en större operation om man lägger till text i början istället för slutet. Faktum är att det kan bli riktigt kostsamt med en vektor- eller ArrayList-implementation.

Visa signatur

Kom-pa-TI-bilitet

Permalänk
Medlem
Skrivet av Teknocide:

Jag hängde inte med på vad indexet skulle användas till tror jag.
Du har naturligtvis rätt i att det blir en större operation om man lägger till text i början istället för slutet. Faktum är att det kan bli riktigt kostsamt med en vektor- eller ArrayList-implementation.

Indexet används för att hitta ordets objekt i en Hashtabell.
wordsTable.get(2) returnerar alltså Objektet för ordet ipsum.

Permalänk
Medlem

Vad innehåller objektet?

för att förtydliga: som jag förstår det så ska det innehålla information om ordet (ipsum i det här fallet) men ordets position är ju redan känt, annars vet man inte vilket index man ska läsa.

Visa signatur

Kom-pa-TI-bilitet

Permalänk
Medlem
Skrivet av Teknocide:

Vad innehåller objektet?

  • Ordet

  • Ordet före (eventuell) autokorrigering gjorts

  • En referens till en lista med förslag på andra ord

Permalänk
Medlem
Skrivet av MrMadMan:
  • Ordet

  • Ordet före (eventuell) autokorrigering gjorts

  • En referens till en lista med förslag på andra ord

Jag kan vara helt ute och cykla nu, är ganska trött, men visst känner man ordet när man hittat indexet, eftersom det står framför..?

Vad jag menar är att indexet inte löser något problem som jag förstår det; för att hitta det måste man ändå arbeta sig igenom textmassan. Stämmer inte det?

Visa signatur

Kom-pa-TI-bilitet

Permalänk
Medlem
Skrivet av Teknocide:

Jag kan vara helt ute och cykla nu, är ganska trött, men visst känner man ordet när man hittat indexet, eftersom det står framför..?

Vad jag menar är att indexet inte löser något problem som jag förstår det; för att hitta det måste man ändå arbeta sig igenom textmassan. Stämmer inte det?

Problemet är inte att hitta ordet. Det kan man göra bara genom att sätta textmarkören där (den hamnar då nära ordets "index"). Syftet är att koppla ett ord i texten till ett objekt som har mer information än bara textsträngen.