/* * Ce fichier contient le code qui ajoute les deux fonctions suivantes * au serveur MySQL: * * PHONEX2S("une chaine") -> retourne un chaine correspondant à la valeur * phonétique du paramètre * PHONEX2R("une chaine") -> retourne un réel * * L'utilisation d'une ou l'autre des fonctions dépend de votre compromis * entre lisbilité et performance/taille des tables. * * Intégration dans MySQL: * * mysql> CREATE FUNCTION phonex2s RETURNS STRING SONAME "phonex2.so"; * mysql> CREATE FUNCTION phonex2r RETURNS STRING SONAME "phonex2.so"; * * Suppression de MySQL: * * mysql> DROP FUNCTION phonex2s; * mysql> DROP FUNCTION phonex2r; */ #include #include #include #include #include #include #ifdef WITH_MAIN static int debug = 0; #else static int debug = 0; #endif /* taille max en car. d'une conversion de chaine en son phonex: */ #define PHONEX_MAXSZ 16 /* différents drapeaux qui influent sur l'algorithme: */ #define FLAG_NORMAL 0x0000 #define FLAG_EFINAL 0x0001 #define FLAG_EACCENT 0x0002 /* liste des caractères autorisés dans la conversion en phonex: */ static unsigned char *finals = "12345efghiklnorstuwxyz"; static void phonex2(unsigned char *s, unsigned int flag); /* * Interface avec MySQL: */ my_bool phonex2s_init(UDF_INIT *initid, UDF_ARGS *args, char *message) { initid->maybe_null = 0; if (args->arg_count < 1 || args->arg_count > 3) { strcpy(message,"PHONEX2S syntax is PHONEX2S(string[,flag[,maxsize]]) with maxsize <= 16"); return 1; } if (args->arg_type[0] != STRING_RESULT) { strcpy(message,"PHONEX2S needs a STRING Parameter"); return 1; } if (args->arg_count >= 2 &&args->arg_type[1] != INT_RESULT) { strcpy(message,"Second Parameter of PHONEX2S must be an INT (the flag)"); return 1; } if (args->arg_count >= 3) { if (args->arg_type[2] != INT_RESULT) { strcpy(message,"Third Parameter of PHONEX2S must be an INT (the maximum size)"); return 1; } if (*((long long *)args->args[2]) > 16) { strcpy(message,"Third Parameter of PHONEX2S must be <= 16"); return 1; } } return 0; } void phonex2s_deinit(UDF_INIT *initid) { } my_bool phonex2r_init(UDF_INIT *initid, UDF_ARGS *args, char *message) { initid->maybe_null = 0; if (args->arg_count < 1 || args->arg_count > 2) { strcpy(message,"PHONEX2R syntax is PHONEX2R(string[,flag])"); return 1; } if (args->arg_type[0] != STRING_RESULT) { strcpy(message,"PHONEX2R needs a STRING Parameter"); return 1; } if (args->arg_count >= 2 && args->arg_type[1] != INT_RESULT) { strcpy(message,"Second Parameter of PHONEX2R must be an INT (the flag)"); return 1; } return 0; } void phonex2r_deinit(UDF_INIT *initid) { } /* * Implémentation: */ char *phonex2s( UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error) { unsigned int flag = 0; unsigned int size = 0; float res; unsigned int len = args->lengths[0]; unsigned char *copy = (unsigned char *)malloc(len+1); memcpy(copy,args->args[0],len); copy[len] = '\0'; if (args->arg_count > 1) { flag = *((long long *)args->args[1]); } if (args->arg_count > 2) { size = *((long long *)args->args[2]); } phonex2(copy,flag); len = strlen(copy); if (size) *length = (size < len) ? size : len; else *length = len; memcpy(result,copy,*length); *is_null = *error = 0; free(copy); return result; } double phonex2r(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error) { unsigned int flag = 0; float phonex = 0; int indice = 0; int base = strlen(finals); unsigned int len = args->lengths[0]; unsigned char *p,*copy = (unsigned char *)malloc(len+1); memcpy(copy,args->args[0],len); copy[len] = '\0'; if (args->arg_count > 1) { flag = *((long long *)args->args[1]); } phonex2(copy,flag); *is_null = *error = 0; /* chiffrement numerique en ignorant les car. non autorises: */ p = copy; indice = 0; while (*p) { unsigned char *rank = strchr(finals,*p); /* normalement tous les car. sont corrects */ phonex += (rank-finals) * powf(indice,base); indice++; p++; } free(copy); return phonex; } /* * Note: l'écriture 'p+2' est sure car si 'p+2' pointe au-delà du dernier * caractère de la chaine, on ne recopiera jamais après le '\0' final * * Les opérations doivent être faites dans le bon ordre (par exemple: * ph->f avant traitement du 'h' !) * * Le contenu de la chaine passée en paramètre est modifié. C'est la * responsabilité de la fonction appelante de passer une copie de * l'original si nécessaire. Le contenu de la chaine retournée a une * longueur de 16 caractères maximum. */ static void phonex2(unsigned char *copy, unsigned int flag) { unsigned char *p,achar; unsigned char *voyelles1 = "aeiouy"; unsigned char *voyelles2 = "aeiouy1234"; /* Cas trivial de la chaine vide: */ if (!*copy) return; /* - remplace les accents et autres caracteres "bizarres". * - le Y/y devient i * - la cédille devient 'ss' * - les autres cars. sont mis en minuscules */ p = copy; while (*p) { if ((*p >= 0xE0 && *p <= 0xE6) || (*p >= 0xC0 && *p <= 0xC6)) { *p++ = 'a'; continue; } if ((*p >= 0xE8 && *p <= 0xEB) || (*p >= 0xC8 && *p <= 0xCB)) { *p++ = 'e'; continue; } if ((*p >= 0xD2 && *p <= 0xD6) || (*p >= 0xF2 && *p <= 0xF6)) { *p++ = 'o'; continue; } if ((*p >= 0xCC && *p <= 0xCF) || (*p >= 0xEC && *p <= 0xEF)) { *p++ = 'i'; continue; } if ((*p >= 0xF9 && *p <= 0xFC) || (*p >= 0xD9 && *p <= 0xDC)) { *p++ = 'u'; continue; } if (*p == 'Y' || *p == 'y') { *p++ = 'i'; continue; } if (*p == 0xC7 || *p == 0xE7) { *p++ = 's'; memmove(p,p+1,strlen(p)); *p++ = 's'; continue; } *p++ = tolower(*p); } if (debug) printf("S1(accents): %s\n",copy); /* Remplace 'ph' par 'f': */ p = copy; while (*p) { if (*p == 'p' && *(p+1) == 'h') { *p = 'f'; memmove(p+1,p+2,strlen(p+1)); } *p++; } if (debug) printf("S2(ph->f): %s\n",copy); /* Supprime les 'h' muets, c'est à dire, les 'h' qui ne sont pas précédés * ni d'un 'c', ni d'un 's': */ p = copy; while (*p) { if (*p == 'h') { if (p == copy) { /* 'h' initial: */ memmove(copy,p+1,strlen(copy)); continue; } if (*(p-1) != 'c' && *(p-1) != 's') { memmove(p,p+1,strlen(p)); continue; } } p++; } if (debug) printf("S3(h): %s\n",copy); /* Remplacement de 'g' par 'k' devant 'an/am/ain/aim': */ p = copy; while (*p) { if (*p != 'g' || *(p+1) != 'a') { p++; continue; } if (*(p+2) == 'n' || *(p+2) == 'm' ) { *p++ = 'k'; continue; } if (*(p+2) == 'i') { if (*(p+3) == 'n' || *(p+3) == 'm' ) { *p++ = 'k'; continue; } } p++; } if (debug) printf("S4(g->k): %s\n",copy); /* - remplacement de aina,eina,aima,eima par yna * - remplacement de aine,eine,aime,eime par yne * - remplacement de aini,eini,aimi,eimi par yni * - remplacement de aino,eino,aimo,eimo par yno * - remplacement de ainu,einu,aimu,eimu par ynu */ p = copy; while (*p) { unsigned char v; if (*p != 'a' && *p != 'e') { p++; continue; } if (*(p+1) != 'i') { p++; continue; } if (*(p+2) != 'n' && *(p+2) != 'm') { p++; continue; } v = *(p+3); if (!*(p+3) || !strchr(voyelles1,v)) { p++; continue; } *p = 'y'; *(p+1) = 'n'; *(p+2) = v; memmove(p+3,p+4,strlen(p+3)); p++; } if (debug) printf("S5(aine): %s\n",copy); /* - remplacement de eau par o * - remplacement de oua par 2 * - remplacement de ein par 4 * - remplacement de ain par 4 */ p = copy; while (*p) { if (*p == 'e' && *(p+1) == 'a' && *(p+2) == 'u') { *p++ = 'o'; memmove(p,p+2,strlen(p+1)); continue; } if (*p == 'o' && *(p+1) == 'u' && *(p+2) == 'a') { *p++ = '2'; memmove(p,p+2,strlen(p+1)); continue; } if (*p == 'e' && *(p+1) == 'i' && *(p+2) == 'n') { *p++ = '4'; memmove(p,p+2,strlen(p+1)); continue; } if (*p == 'a' && *(p+1) == 'i' && *(p+2) == 'n') { *p++ = '4'; memmove(p,p+2,strlen(p+1)); continue; } p++; } if (debug) printf("S6(eau): %s\n",copy); /* - remplacement de ai par y * - remplacement de ei par y * - remplacement de ee par y * - remplacement de er par yr * - remplacement de ess par yss * - remplacement de et par yt * - remplacement de ez par yz */ p = copy; while (*p) { if (*p == 'a' && *(p+1) == 'i') { *p++ = 'y'; memmove(p,p+1,strlen(p)); continue; } if (*p == 'e' && *(p+1) == 'i') { *p++ = 'y'; memmove(p,p+1,strlen(p)); continue; } if (*p == 'e' && *(p+1) == 'e') { *p++ = 'y'; memmove(p,p+1,strlen(p)); continue; } if (*p == 'e' && (*(p+1) == 'r' || *(p+1) == 't' || *(p+1) == 'z')) { *p++ = 'y'; continue; } if (*p == 'e' && *(p+1) == 's' && *(p+2) == 's') { *p++ = 'y'; continue; } p++; } if (debug) printf("S7(er->yr): %s\n",copy); /* suppression des lettres doubles: */ p = copy; while (*p) { if (*p == *(p+1)) { memmove(p,p+1,strlen(p)); p--; } p++; } if (debug) printf("S15(nn): %s\n",copy); /* - remplacement de an par 1 * - remplacement de am par 1 * - remplacement de en par 1 * - remplacement de em par 1 * - remplacement de in par 4 * à condition que ces modèles ne soient ni suivis d'une voyelle * ni d'un son 1 à 4 */ p = copy; while (*p) { if ((*p == 'a' || *p == 'e') && (*(p+1) == 'n' || *(p+1) == 'm')) { if (!*(p+2) || !strchr(voyelles2,*(p+2))) { *p++ = '1'; memmove(p,p+1,strlen(p)); continue; } } if (*p == 'i' && *(p+1) == 'n') { if (!*(p+2) || !strchr(voyelles2,*(p+2))) { *p++ = '4'; memmove(p,p+1,strlen(p)); continue; } } p++; } if (debug) printf("S8(an->1): %s\n",copy); /* remplacement du 'z' par 's' s'il est précédé (ou en tête de mot) et suivi d'une voyelle * ou d'un son 1 à 4: */ p = copy; if (*p == 'z' && *(p+1) && strchr(voyelles2,*(p+1))) *p = 's'; while (*p) { if (*p == 'z' && *(p+1)) { unsigned char v1 = *(p-1); unsigned char v2 = *(p+1); if (strchr(voyelles2,v1) && v2 && strchr(voyelles2,v2)) { *p = 's'; } } p++; } if (debug) printf("S9(z->s): %s\n",copy); /* - remplacement de oe par e * - remplacement de eu par e * - remplacement de au par o * - remplacement de oi par 2 * - remplacement de ou par 3 */ p = copy; while (*p) { if (*p == 'o' && *(p+1) == 'e') { *p++ = 'e'; memmove(p,p+1,strlen(p)); continue; } if (*p == 'e' && *(p+1) == 'u') { *p++ = 'e'; memmove(p,p+1,strlen(p)); continue; } if (*p == 'a' && *(p+1) == 'u') { *p++ = 'o'; memmove(p,p+1,strlen(p)); continue; } if (*p == 'o' && *(p+1) == 'i') { *p++ = '2'; memmove(p,p+1,strlen(p)); continue; } if (*p == 'o' && *(p+1) == 'u') { *p++ = '3'; memmove(p,p+1,strlen(p)); continue; } p++; } if (debug) printf("S10(oe/oi): %s\n",copy); /* - remplacement de ch par 5 * - remplacement de sch par 5 * - remplacement de sh par 5 * - remplacement de ss par s * - remplacement de sc par s si suivi d'un "e" ou d'un "i" */ p = copy; while (*p) { if (*p == 'c' && *(p+1) == 'h') { *p++ = '5'; memmove(p,p+1,strlen(p)); continue; } if (*p == 's' && *(p+1) == 'h') { *p++ = '5'; memmove(p,p+1,strlen(p)); continue; } if (*p == 's' && *(p+1) == 's') { p++; memmove(p,p+1,strlen(p)); continue; } if (*p == 's' && *(p+1) == 'c' && *(p+2) == 'h') { *p++ = '5'; memmove(p,p+2,strlen(p+1)); continue; } if (*p == 's' && *(p+1) == 'c' && (*(p+2) == 'e' || *(p+2) == 'i') ) { p++; memmove(p,p+1,strlen(p)); continue; } p++; } if (debug) printf("S11(ch->5): %s\n",copy); /* remplacement du 'c' par un 's' s'il est suivi d'un e/i: */ p = copy; while (*p) { if (*p == 'c' && (*(p+1) == 'e' || *(p+1) == 'i')) { *p = 's'; } p++; } if (debug) printf("S12(c->s): %s\n",copy); /* - remplacement de c par k * - remplacement de q par k * - remplacement de qu par k * - remplacement de gu par k * - remplacement de ga par ka * - remplacement de go par ko */ p = copy; while (*p) { if (*p == 'c' || *p == 'q') { *p++ = 'k'; continue; } if ((*p == 'q' || *p == 'g') && *(p+1) == 'u') { *p++ = 'k'; memmove(p,p+1,strlen(p)); continue; } if (*p == 'g' && (*(p+1) == 'a' || *(p+1) == 'o')) { *p++ = 'k'; continue; } p++; } if (debug) printf("S13(c->k): %s\n",copy); /* - remplacement de a par o * - remplacement de d et p par t * - remplacement de j par g * - remplacement de b et v par f * - remplacement de m par n */ p = copy; while (*p) { if (*p == 'a') { *p++ = 'o'; continue; } if (*p == 'd' || *p == 'p') { *p++ = 't'; continue; } if (*p == 'j') { *p++ = 'g'; continue; } if (*p == 'b' || *p == 'v') { *p++ = 'f'; continue; } if (*p == 'm') { *p++ = 'n'; continue; } p++; } if (debug) printf("S14(d->t): %s\n",copy); /* Option: convertit les 'y' en 'e': */ if (!(flag & FLAG_EACCENT)) { p = copy; while (*p) { if (*p == 'y') *p = 'e'; p++; } if (debug) printf("S17(y->e): %s\n",copy); } /* - suppression des finales t,x,s,z * - suppression du e final après une consonne * (fait en deux fois pour eliminer les finales -ez par exemple) */ if (strlen(copy) > 1) { achar = copy[strlen(copy)-1]; if (achar == 'x' || achar == 't' || achar == 's' || achar == 'z') { copy[strlen(copy)-1] = '\0'; } } if (!(flag & FLAG_EFINAL)) { if (strlen(copy) > 1) { achar = copy[strlen(copy)-1]; if (achar == 'e' && !strchr(voyelles1,copy[strlen(copy)-2])) { copy[strlen(copy)-1] = '\0'; } } if (debug) printf("S16(txsz): %s\n",copy); } /* suppression des lettres doubles (2eme fois): */ p = copy; while (*p) { if (*p == *(p+1)) { memmove(p,p+1,strlen(p)); p--; } p++; } if (debug) printf("S15(nn): %s\n",copy); /* Ne retourne que les caractères autorisés avec un * maximum de 16 car. dans la chaine: */ p = copy; while (*p && (p-copy) < PHONEX_MAXSZ) { if (!strchr(finals,*p)) { memmove(p,p+1,strlen(p)); continue; } p++; } *p = '\0'; } #ifdef WITH_MAIN void Check(char *s1, char *s2) { char buff1[64],buff2[64]; printf("Compare %s and %s: ",s1,s2); strcpy(buff1,s1); strcpy(buff2,s2); phonex2(buff1,0); phonex2(buff2,0); printf("%s\n",(strcmp(buff1,buff2)) ? "no match" : "match"); } int main(int argc, char *argv[]) { char buff[64]; int flag; if (argc > 1 && argv[1][1] == 'd') debug = 1; /* tests automatiques: */ Check("phaure","fort"); Check("elephant","ellefan"); Check("arrivez","arivee"); printf("flag: "); scanf("%d",&flag); /* tests interactifs: */ for (;;) { printf("Chaine: "); scanf("%s",buff); phonex2(buff,flag); printf("phonex=%s\n",buff); } return 0; } #endif /* EOF */