OVH Cloud OVH Cloud

Lien alphabetiques type carnet d'adress e

6 réponses
Avatar
fff
Salut à tous,

Je cherche à faire un carnet d'adresses où j'aurais une liste de lien du
type:

# | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q |
R | S | T | U | V | W | X | Y | Z

En cliquant sur une lettre les personnes ou sociétés dont le nom
commence par cette lettre s'affichent. Aucun problème de formattage HTML
ou boucle PHP.

J'ai un table (plusieurs en fait) en UTF-8 et toutes mes pages sont bien
en UTF-8 également.

Ca marche pas mal avec le code ci-dessous mais :
- Tous les noms commençant par des caractères accentués se retrouvent
sous 'A' (voir le code ci-dessous pour comprendre)
- Je ne sais pas comment faire pour retrouver tous les noms commençant
par autre chose qu'une lettre sous '#'

Voici une version du code (simplifiée) que j'utilise. Ca marche sauf que
ça marche pas comme je veux (voir ci-dessus).

<?php
// Retrieve the letter passed via the URL
$curr_letter = $_REQUEST['letter'];

// Build the SQL string
$sql = "SELECT * FROM people WHERE lastname LIKE '$curr_letter%'";
?>

Je suis prenneur de tout conseil, code ou URL.

Merci de votre patience.

PS:
J'ai posté une version anglaise sur alt.php.sql (c'est pas du cross
posting puisque c'est une traduction, OK ?)

6 réponses

Avatar
Olivier Miakinen
Bonjour,


Je cherche à faire un carnet d'adresses où j'aurais une liste de lien du
type:

# | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q |
R | S | T | U | V | W | X | Y | Z

En cliquant sur une lettre les personnes ou sociétés dont le nom
commence par cette lettre s'affichent.

[...]

Voici une version du code (simplifiée) que j'utilise. Ca marche sauf que
ça marche pas comme je veux (voir ci-dessus).

<?php
// Retrieve the letter passed via the URL
$curr_letter = $_REQUEST['letter'];

// Build the SQL string
$sql = "SELECT * FROM people WHERE lastname LIKE '$curr_letter%'";
?>


De deux choses l'une.

Soit il existe une requête SQL qui compare les chaînes en rassemblant
les caractères accentués en fonction de LC_COLLATE, et dans ce cas le
bon groupe sera plus probablement celui sur les bases de données :
fr.comp.applications.sgbd.

Soit tu stockes dans ta base de donnée, en plus du nom, la lettre que tu
voudrais y voir associée, et tu peux chercher cette lettre avec PHP.
L'avantage de cette méthode, c'est que pour la recherche tu n'utiliseras
pas LIKE mais l'égalité.

Je suppose qu'on est dans le second cas (puisque c'est le groupe PHP).
Si tu étais en ISO-Latin-1, il serait facile de récupérer le premier
caractère de ta chaîne avec accent, passer un petit coup de strtr()¹
pour remplacer les äÄàÀáÁ par A, etc. En utf-8, c'est plus complexe mais
c'est faisable, et cela a peut-être déjà été fait. Une suggestion qui
vaut ce qu'elle vaut : transformer ta chaîne de utf-8 en iso-latin-1 par
utf8_decode()² avant de faire le strtr(). L'inconvénient, c'est que des
caractères n'existant pas en latin-1 (par exemple le s avec circonflexe
inversé) ne seront pas traduits en caractères sans accent.

En espérant avoir aidé,
--
Olivier Miakinen
¹ http://www.php.net/manual/en/function.strtr.php
² http://www.php.net/manual/en/function.utf8-decode.php

Avatar
fff
Bonjour,


Je cherche à faire un carnet d'adresses où j'aurais une liste de lien du


De deux choses l'une.

Soit il existe une requête SQL qui compare les chaînes en rassemblant
les caractères accentués en fonction de LC_COLLATE, et dans ce cas le
bon groupe sera plus probablement celui sur les bases de données :
fr.comp.applications.sgbd.


J'ai posté un message sur ce groupe, merci du conseil. En effet utiliser
LC_COLLATE peut être une solution, mais je suis assez perdu quant à son
utilisation.

Soit tu stockes dans ta base de donnée, en plus du nom, la lettre que tu
voudrais y voir associée, et tu peux chercher cette lettre avec PHP.
L'avantage de cette méthode, c'est que pour la recherche tu n'utiliseras
pas LIKE mais l'égalité.


Le problème dans ce cas c'est bien de savoir associer la lettre entrée
automatiquement. Je n'ai pas envie de devoir sélectionner la lettre
manuellement. De plus je souhaite faire partager cette application à des
utilisateurs basiques (encore plus basiques que moi) et donc je ne peux
pas leur faire confiance pour renseigner ce champ stratégique.

Je suppose qu'on est dans le second cas (puisque c'est le groupe PHP).
Si tu étais en ISO-Latin-1, il serait facile de récupérer le premier
caractère de ta chaîne avec accent, passer un petit coup de strtr()¹
pour remplacer les äÄàÀáÁ par A, etc. En utf-8, c'est plus complexe mais
c'est faisable, et cela a peut-être déjà été fait. Une suggestion qui
vaut ce qu'elle vaut : transformer ta chaîne de utf-8 en iso-latin-1 par
utf8_decode()² avant de faire le strtr(). L'inconvénient, c'est que des
caractères n'existant pas en latin-1 (par exemple le s avec circonflexe
inversé) ne seront pas traduits en caractères sans accent.



En espérant avoir aidé,


Oui beaucoup, merci de ton aide.


Avatar
Olivier Miakinen

Soit il existe une requête SQL qui compare les chaînes en rassemblant
les caractères accentués en fonction de LC_COLLATE, et dans ce cas le
bon groupe sera plus probablement celui sur les bases de données :
fr.comp.applications.sgbd.


J'ai posté un message sur ce groupe, merci du conseil.


J'ai vu. J'ai également vu que tu n'as pas fait très attention au nom du
groupe : il commence par « fr. », ce qui signifie qu'il est tout aussi
francophone que l'est fr.comp.lang.php. ;-)

En effet utiliser LC_COLLATE peut être une solution, mais je suis
assez perdu quant à son utilisation.


La principale utilisation dans ton cas serait d'utiliser strcoll :
<http://www.php.net/manual/fr/function.strcoll.php> mais de même que
dans ma proposition avec utf8_decode() + strtr() ce serait lors du
remplissage de la base de données, pas lors de sa consultation.

Note d'ailleurs que seul l'ajout d'un champ particulier te permettra de
traiter facilement le cas « autres caractères (#) ».

[...]


Le problème dans ce cas c'est bien de savoir associer la lettre entrée
automatiquement. Je n'ai pas envie de devoir sélectionner la lettre
manuellement. De plus je souhaite faire partager cette application à des
utilisateurs basiques (encore plus basiques que moi) et donc je ne peux
pas leur faire confiance pour renseigner ce champ stratégique.


Il ne faut surtout pas le faire à la main ni demander à tes utilisateurs
de le faire ! Ce genre de manip complètement mécanique doit être bien
sûr automatisée. Ma solution à base d'utf8_decode ne te convient
peut-être pas à cause des œ et Œ absents d'ISO-Latin-1, mais une autre
solution serait peut-être envisageable.

Tout d'abord une question : souhaites-tu pouvoir reconnaître d'autres
caractères accentués que ceux qui sont dans ISO-Latin-9 :
<http://www.miakinen.net/vrac/codeset?set=isolatin9> ?
Sinon, c.-à-d. si cette liste te suffit, je dois pouvoir faire quelque
chose pour toi.

--
Olivier Miakinen
Non, monsieur le juge, je vous le jure : jamais je n'ai cité
Bruxelles dans ma signature.


Avatar
Olivier Miakinen
Le 28/02/2005 13:01, je répondais à fff :

Il ne faut surtout pas le faire à la main ni demander à tes utilisateurs
de le faire ! Ce genre de manip complètement mécanique doit être bien
sûr automatisée. Ma solution à base d'utf8_decode ne te convient
peut-être pas à cause des œ et Œ absents d'ISO-Latin-1, mais une autre
solution serait peut-être envisageable.


Voici une solution qui devrait fonctionner. Attention, je préviens d'avance
les quoteurs fous que s'ils répondent à mon article sans suivre les conseils
de <http://www.giromini.org/usenet-fr/repondre.html> ils n'ont aucune chance
de voir leur article approuvé dans ce groupe.


<?php

error_reporting(E_ALL);

define("NUL","#");

$UNICODE_LATIN_ALPHA = array(
/* Basic Latin (i.e. 7bit ASCII) */
0x40 => NUL,"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O",
0x50 => "P","Q","R","S","T","U","V","W","X","Y","Z",NUL,NUL,NUL,NUL,NUL,
0x60 => NUL,"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o",
0x70 => "p","q","r","s","t","u","v","w","x","y","z",NUL,NUL,NUL,NUL,NUL,
/* Latin-1 Supplement */
0xC0 => "A","A","A","A","A","A","A","C","E","E","E","E","I","I","I","I",
0xD0 => NUL,"N","O","O","O","O","O",NUL,"O","U","U","U","U","Y",NUL,"s",
0xE0 => "a","a","a","a","a","a","a","c","e","e","e","e","i","i","i","i",
0xF0 => NUL,"n","o","o","o","o","o",NUL,"o","u","u","u","u","y",NUL,"y",
/* Latin Extended-A */
0x100 => "A","a","A","a","A","a","C","c","C","c","C","c","C","c","D","d",
0x110 => "D","d","E","e","E","e","E","e","E","e","E","e","G","g","G","g",
0x120 => "G","g","G","g","H","h","H","h","I","i","I","i","I","i","I","i",
0x130 => "I","i","I","i","J","j","K","k",NUL,"L","l","L","l","L","l","L",
0x140 => "l","L","l","N","n","N","n","N","n",NUL,NUL,NUL,"O","o","O","o",
0x150 => "O","o","O","o","R","r","R","r","R","r","S","s","S","s","S","s",
0x160 => "S","s","T","t","T","t","T","t","U","u","U","u","U","u","U","u",
0x170 => "U","u","U","u","W","w","Y","y","Y","Z","z","Z","z","Z","z","s",
/* Kludge : don't need to remove the last comma when we add values */
NUL
);

/*
* Function: get_one_unicode_from_utf8
*
* Purpose:
* Get unicode value of the first character in a utf8-encoded string.
* Any error, e.g. an empty string, a string with wrong utf-8 encoding,
* or a utf-8 string which starts with a character whose code is greater
* than U+0800, will return -1.
*
* Parameter:
* $utf8_string : a string, supposedly encoded in UTF-8.
*
* Return value:
* 0..0x7FF or -1
*
* Bugs :
* This function was written to be useable for unicode characters
* in range U+0000 - U+0200 only. Actually it works for characters in
* range U+0000 - U+07FF, but it doesn't cover anything else.
*/
function get_one_unicode_from_utf8($utf8_string)
{
if (strlen($utf8_string) < 1) {
return -1;
}
$c1 = ord($utf8_string);
if ($c1 <= 0x7F) {
return $c1;
}
if (strlen($utf8_string) < 2) {
return -1;
}
$c1 &= 0x1F;
$c2 = ord($utf8_string{1});
if (($c2 < 0x80) || ($c2 > 0xBF)) {
return -1;
}
$c2 &= 0x3F;
return (($c1 << 6) + $c2);
}

/*
* Function: get_latin_alpha_initial
*
* Purpose:
* Get an equivalent latin1 alphabetic character for the first character
* of a UTF-8 string. As an example, for a string which begins with an
* uppercase E, or E acute, E grave, etc., will return "E".
*
* Parameter:
* $utf8_string : a string, supposedly encoded in UTF-8.
*
* Return value:
* A letter in range "A".."Z" or "a".."z", as appropriate.
* When the string doesn't begin with a latin letter, or in case of an
* error, this function returns "#".
*
* Bugs :
* Only certain Unicode characters, in range U+0000 .. U+0180, are
* currently recognized (i.e. ASCII, Latin-1 Supplement and Latin
* Extended-A). It is possible to add characters of Latin Extended-B
* by modifying $UNICODE_LATIN_ALPHA[] array. In the unlikely case
* where Latin characters would also exist above U+0800, it would be
* also necessary to change the function get_one_unicode_from_utf8().
*/
function get_latin_alpha_initial($utf8_string)
{
global $UNICODE_LATIN_ALPHA;

$unicode = get_one_unicode_from_utf8($utf8_string);
if ($unicode < 0) {
return NUL;
}
if (!isset($UNICODE_LATIN_ALPHA[$unicode])) {
return NUL;
}
return $UNICODE_LATIN_ALPHA[$unicode];
}

/*
* Function: get_latin_uppercase_initial
*
* Purpose:
* Same as get_latin_alpha_initial(), but always returns uppercase
* letters.
*
* Parameter:
* $utf8_string : a string, supposedly encoded in UTF-8.
*
* Return value:
* A letter in range "A".."Z" as appropriate, even when the initial
* letter was a lowercase one.
* When the string doesn't begin with a latin letter, or in case of an
* error, this function returns "#".
*
* Bugs :
* The same as get_latin_alpha_initial().
*/
function get_latin_uppercase_initial($utf8_string)
{
return strtoupper(get_latin_alpha_initial($utf8_string));
}

?>

--
Olivier Miakinen
Non, monsieur le juge, je vous le jure : jamais je n'ai cité
Bruxelles dans ma signature.

Avatar
fff
Olivier,

Avant tout, désolé d'avoir été si long à répondre, je me suis cogné à un
problème de compatibilité CSS sous IE. très crispant.

En effet la table ISO-8859-15 me semble largement suffisante pour mes
besoins. Je ne sais pas ce que je ferais de tout façon si des japonais
ou des arabes venaient à utiliser ce carnet d'adresses...

Après avoir décortiqué ton code je crois que c'est un excellente solution.

Je fais un copier-coller sans vergogne et je teste une implémentation
rapide et je te fais part du résultat dès que possible.

merci encore !

Sébastien
Avatar
Olivier Miakinen

Avant tout, désolé d'avoir été si long à répondre, je me suis cogné à un
problème de compatibilité CSS sous IE. très crispant.


Haha... si cela peut te rassurer, j'ai parfois attendu plus d'un mois
avant de répondre à quelqu'un dans les news. Par ailleurs, je viens de
voir que tu m'avais écrit en privé aussi, mais j'y répondrai ensuite.

En effet la table ISO-8859-15 me semble largement suffisante pour mes
besoins.


Je ne sais pas si tu as remarqué, mais finalement au lieu de ne rajouter
que les sept caractères alphabétiques de ISO-8859-15 (ŠšŽžŒœŸ) j'en ai
rajouté cent vingt-quatre, à savoir les 128 de la page
<http://www.unicode.org/charts/PDF/U0100.pdf>, moins les quatre qui ne
sont pas vraiment des lettres standards avec accent.

Si le cœur t'en dit, n'hésite pas à rajouter aussi ceux de la page
<http://www.unicode.org/charts/PDF/U0180.pdf>, après quoi on devrait
avoir fait le tour de ce qui est assimilable à une lettre de A à Z.

Je ne sais pas ce que je ferais de tout façon si des japonais
ou des arabes venaient à utiliser ce carnet d'adresses...


Ben rien, puisque leurs alphabets ne sont pas basés sur le latin. Tout
caractère non latin donnera '#'.

Après avoir décortiqué ton code je crois que c'est un excellente solution.


Sans aucune modestie, je le crois aussi. C'est d'ailleurs pour cette
raison que je me suis appliqué à séparer les différentes parties, et que
j'ai publié le code source sur mon site web :
<http://www.miakinen.net/vrac/source/initial>.

Merci de me signaler d'éventuels bugs ou améliorations, pour que je
mette cette page à jour.

Je fais un copier-coller sans vergogne et je teste une implémentation
rapide et je te fais part du résultat dès que possible.


Je vais maintenant lire ta réponse par courriel.