Online spellingcontrole

Uit Simonswiki

Ga naar: navigatie, zoeken

Als je op een webpagina wilt laten zien hoe Hunspell werkt, dan is het niet efficiƫnt om Hunspell voor ieder te controleren woord opnieuw op te starten, het initialiseren kost namelijk best veel tijd. Wat je wil is het 1 keer opstarten en het dan op verzoek woorden laten checken. En wel zo dat het van meerdere sessies "tegelijk" verzoeken kan afhandelen zonder in de war te raken.

Wat ik heb gedaan is de Hunspell-library aanroepen in een programmaatje dat als server draait (dus maar 1 keer Hunspell initialiseren) en dat op een UDP-socket verzoeken voor het controleren van een woord beantwoordt. Het php-script verstuurt via een UDP-socket het te controleren woord en ontvangt het antwoord per kerende post.

Het grote voordeel van UDP ten opzichte van TCP is dat het implementeren van een "single process concurrent server" er een heel stuk simpeler van wordt, zie hier beneden. Omdat rekwest en respons gemakkelijk in 1 IP-pakket passen is streaming ook helemaal niet nodig. Een nadeel van UDP is dat het transport van pakketten niet gegarandeerd is, zelfs binnen hetzelfde systeem, maar hiermee is in het php-script rekening gehouden.

De relevante code van server en php-script wordt hieronder getoond. Mail mij voor vragen: simon {punt} o {apenstaartje} brousant {punt} nl

opmerking over builden van Hunspell

Mogelijk moet je na het builden en installeren nog (als root) ldconfig uitvoeren om te zorgen dat de library kan worden gevonden.

spell check server

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "hunspell.h"
#define MYPORT 5678
#define MAXINBUFLEN 100
#define MAXOUTBUFLEN 200
int main(void)
{
   int sockfd;
   struct sockaddr_in my_adress;
   struct sockaddr_in rem_adress;
   int adress_len, word_len, num_bytes;
   char inbuf[MAXINBUFLEN];
   char outbuf[MAXOUTBUFLEN];
   int count=0, i, result;
   Hunhandle *pHunspell;
   char **sugs;
   int numsugs;
   pHunspell=Hunspell_create("./new.aff", "./new.dic");
   if (pHunspell==NULL) {
       perror("Hunspell_create");
       exit(1);
   }

   if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
       perror("socket");
       exit(1);
   }
   my_adress.sin_family = AF_INET;
   my_adress.sin_port = htons(MYPORT);
   my_adress.sin_addr.s_addr = INADDR_ANY;
   memset(&(my_adress.sin_zero), '\0', 8);
   if (bind(sockfd, (struct sockaddr *)&my_adress, sizeof(struct sockaddr)) == -1) {
       perror("bind");
       exit(1);
   }
   printf ("spell check server running...\n");
   adress_len = sizeof(struct sockaddr);
   while (1)
   {
       if ((word_len = recvfrom(sockfd, inbuf, MAXINBUFLEN - 1 , 0, (struct sockaddr *)&rem_adress, (socklen_t *)&adress_len)) == -1) {
       perror("recvfrom");
       continue;
       }
       inbuf[word_len] = '\0';
       printf("%s\n",inbuf);
       if ((result=Hunspell_spell(pHunspell, inbuf))==0) {
            // printf("word not found\n");
            numsugs=Hunspell_suggest (pHunspell, &sugs, inbuf);
            //printf ("number of suggestions=%i\n", numsugs);
            sprintf(outbuf, "%s;0",inbuf);
            for (i=0; i<numsugs; i++) {
                sprintf (outbuf+strlen(outbuf),",%s", sugs[i]);
            }
            Hunspell_free_list(pHunspell, &sugs, numsugs);
       }
       else {
            sprintf(outbuf, "%s;%i", inbuf, result); 
       }
       if ((num_bytes = sendto(sockfd, outbuf , strlen(outbuf) , 0, (struct sockaddr *)&rem_adress, sizeof(struct sockaddr))) == -1) {
       perror("sendto");
       } 
   }
   // should not come here 
   close(sockfd);
   return 0;
}

De server zo compileren:

g++ -lhunspell-1.3 server.c 

Het resultaat, a.out, eventueel een andere naam geven.

php spell check client

(alleen de kern hier getoond. Let wel op dat de codering van de pagina utf-8 is.)

Dit is een demonstratie van Hunspell 1.3.1. <br><br>
<?php
$buf = "";
$name = "localhost";
$port = 5678;
$checkword = ($_POST['checkword']);
echo "<br>";
$socket = socket_create(AF_INET, SOCK_DGRAM, getprotobyname("udp"));
if ($socket == FALSE) {
   echo "socket not created<br>";
}
socket_sendto ($socket, $checkword, strlen($checkword), 0, "localhost", 5678);
$write=NULL;
$except=NULL;
$recword="";
for ($i=0; $i<3; $i++) {
  $read=array($socket);
  $num_changed_sockets= socket_select (&$read, &$write, &$except, 3);
  if ($num_changed_sockets==1) {
     socket_recvfrom($socket, &$buf, 200, 0, &$name, &$port);
     $wordlen=strpos($buf, ";");
     $recword=substr ($buf , 0, $wordlen);
     if ($recword==$checkword) {
        break;
     }
  }
}
if ($recword!=$checkword) {
   echo "<i>geen respons van spellingserver</i><br>"; 
}  
else {
   echo substr ($buf , 0, $wordlen);
   $rescode =substr ($buf, $wordlen+1, 1);
   if ($rescode == "0") {
      echo ": niet goedgekeurd. <br>Suggesties: ";
      echo substr ($buf, $wordlen+3);
   }
   else if ($rescode == "1") {
      echo ": goedgekeurd.";
   }
   else if ($rescode == "2") {
      echo ": goedgekeurd (maar mogelijk verwarrend).";
   } 
} 
echo "<br>" ;
socket_close ($socket);
?>
<form method="post" action="hunspelldemo1.php">
   <p>Woord om te controleren:
       <input type="text" name="checkword">
   </p>
   <p>
       <input type="submit" name="submit" value="Controleren">
   </p>
</form>
Aspecten/acties
Persoonlijke instellingen