Ci-dessous, les différences entre deux révisions de la page.
Les deux révisions précédentes Révision précédente Prochaine révision | Révision précédente | ||
tris_alpha [2011/09/18 10:06] tyrtamos |
tris_alpha [2011/09/21 08:45] tyrtamos |
||
---|---|---|---|
Ligne 5: | Ligne 5: | ||
Trier des chaines de caractères avec Python, c'est facile avec la méthode sort() ou la fonction sorted(), mais l' | Trier des chaines de caractères avec Python, c'est facile avec la méthode sort() ou la fonction sorted(), mais l' | ||
- | Il existe une méthode de base intégrée à Python pour trier des mots selon le dictionnaire français, et décrite par ailleurs sur ce site ([[http:// | + | Il existe une méthode de base intégrée à Python pour trier des mots selon le dictionnaire français, et décrite par ailleurs sur ce site ([[http:// |
Comme exemple d' | Comme exemple d' | ||
Ligne 12: | Ligne 12: | ||
On va donc définir une méthode simplifiée pour la comparaison de 2 chaines de caractères: | On va donc définir une méthode simplifiée pour la comparaison de 2 chaines de caractères: | ||
- | |||
* on définit l' | * on définit l' | ||
- | |||
* on fait la comparaison de 2 textes, caractère par caractère et de gauche à droite, en s' | * on fait la comparaison de 2 textes, caractère par caractère et de gauche à droite, en s' | ||
Ligne 23: | Ligne 21: | ||
</ | </ | ||
- | Ce qui fait que les éventuels caractères non-français rencontrés seront tout de même traités, mais au delà des caractères français. | + | Ce qui fait que les éventuels caractères non-français rencontrés seront tout de même traités, mais au delà des caractères français, et dans l' |
- | La fonction de comparaison prend 2 chaînes de caractères comme argument, et renvoie un nombre entier: | + | Comme le cmp() de Python, |
* négatif si la 1ère chaîne est avant la seconde | * négatif si la 1ère chaîne est avant la seconde | ||
* nul si elles sont égales | * nul si elles sont égales | ||
Ligne 170: | Ligne 168: | ||
Les chemins auraient pu contenir des espaces, des caractères accentués, des chiffres et autres caractères non-alphanumériques($, | Les chemins auraient pu contenir des espaces, des caractères accentués, des chiffres et autres caractères non-alphanumériques($, | ||
- | Avec la classe de comparaison, | + | Avec la comparaison |
+ | |||
+ | Pour déclencher des conversions d' | ||
<code python> | <code python> | ||
Ligne 201: | Ligne 201: | ||
</ | </ | ||
- | Ce qui donne, bien entendu, le même résultat. les chaines non-unicodes ont été simplement convertis en les supposant encodées en ' | + | Ce qui donne, bien entendu, le même résultat. les chaines non-unicodes ont été simplement convertis en les supposant encodées en ' |
Dans des cas plus complexes, on pourrait changer la chaine de comparaison alpha, ou empêcher la correction des voyelles liées. | Dans des cas plus complexes, on pourrait changer la chaine de comparaison alpha, ou empêcher la correction des voyelles liées. | ||
Ligne 311: | Ligne 311: | ||
==== Suppression des accents ==== | ==== Suppression des accents ==== | ||
- | On va créer une fonction de conversion: | + | On va utiliser le module unicodedata: |
<code python> | <code python> | ||
+ | import unicodedata | ||
+ | |||
def sansaccent(ch): | def sansaccent(ch): | ||
""" | """ | ||
- | | + | |
- | | + | |
- | x = u"" | + | |
- | | + | |
- | k = alpha1.find(c) | + | |
- | if k>=0: | + | |
- | x += alpha2[k] | + | |
- | else: | + | |
- | x += c | + | |
- | return x | + | |
</ | </ | ||
+ | |||
+ | Ce code est simple et fait très bien le travail, sauf sur un point: il remplace en plus les espaces insécables par des espaces normaux. | ||
+ | |||
+ | Si vous voulez, comme moi, garder les espaces insécables, | ||
+ | |||
+ | <code python> | ||
+ | import unicodedata | ||
+ | |||
+ | def sansaccent(ch): | ||
+ | """ | ||
+ | r = u"" | ||
+ | for car in unicode(ch): | ||
+ | if car==u" | ||
+ | r += car | ||
+ | else: | ||
+ | carnorm = unicodedata.normalize(' | ||
+ | r += carnorm[0] | ||
+ | return r | ||
+ | </ | ||
+ | |||
+ | Comment ça marche? C'est très simple: | ||
+ | * si car est un caractère accentué, par exemple car=' | ||
+ | * si car n'est pas caractère accentué, unicodedata.normalize(' | ||
Exemple (avec la même chaine que précédemment): | Exemple (avec la même chaine que précédemment): | ||
<code python> | <code python> | ||
+ | print chaine | ||
+ | aAàÀâÂäÄåÅæÆbBcCçÇdDeEéÉèÈêÊëËfFgGhHiIîÎïÏjJkKlLmMnNoOôÔöÖœŒpPqQrRsStTuUùÙûÛüÜvVwWxXyYÿŸzZ | ||
print sansaccent(chaine) | print sansaccent(chaine) | ||
aAaAaAaAaAæÆbBcCcCdDeEeEeEeEeEfFgGhHiIiIiIjJkKlLmMnNoOoOoOœŒpPqQrRsStTuUuUuUuUvVwWxXyYyYzZ | aAaAaAaAaAæÆbBcCcCdDeEeEeEeEeEfFgGhHiIiIiIjJkKlLmMnNoOoOoOœŒpPqQrRsStTuUuUuUuUvVwWxXyYyYzZ | ||
</ | </ | ||
- | Si on veut supprimer les accents seulement sur les majuscules, c'est facile aussi: | + | Si on veut supprimer les accents seulement sur les majuscules, c'est facile aussi, à condition d' |
<code python> | <code python> | ||
def sansaccentmaj(ch): | def sansaccentmaj(ch): | ||
- | """ | + | """ |
- | | + | |
- | alpha2 = u" | + | for car in unicode(ch): |
- | x = u"" | + | |
- | for i,c in enumerate(ch): | + | |
- | | + | |
- | if k>=0: | + | |
- | | + | |
else: | else: | ||
- | | + | |
- | return | + | carcat = unicodedata.category(carnorm[0]) |
+ | if carcat==u' | ||
+ | r += carnorm[0] | ||
+ | else: | ||
+ | r += car | ||
+ | return | ||
</ | </ | ||
Ligne 355: | Ligne 376: | ||
<code python> | <code python> | ||
+ | print chaine | ||
+ | aAàÀâÂäÄåÅæÆbBcCçÇdDeEéÉèÈêÊëËfFgGhHiIîÎïÏjJkKlLmMnNoOôÔöÖœŒpPqQrRsStTuUùÙûÛüÜvVwWxXyYÿŸzZ | ||
print sansaccentmaj(chaine) | print sansaccentmaj(chaine) | ||
aAàAâAäAåAæÆbBcCçCdDeEéEèEêEëEfFgGhHiIîIïIjJkKlLmMnNoOôOöOœŒpPqQrRsStTuUùUûUüUvVwWxXyYÿYzZ | aAàAâAäAåAæÆbBcCçCdDeEéEèEêEëEfFgGhHiIîIïIjJkKlLmMnNoOôOöOœŒpPqQrRsStTuUùUûUüUvVwWxXyYÿYzZ | ||
</ | </ | ||
+ | Et, en ne changeant qu'un seul caractère dans la fonction précédente, | ||
+ | |||
+ | \\ | ||
On peut dès lors dans les tri utiliser ces fonctions de correction seules ou combinées avec les précédentes. | On peut dès lors dans les tri utiliser ces fonctions de correction seules ou combinées avec les précédentes. | ||
- | Par exemple: convertir en majuscules sans accent: | + | Par exemple: convertir en majuscules sans accent |
<code python> | <code python> | ||
Ligne 454: | Ligne 480: | ||
* x = chaîne à rechercher | * x = chaîne à rechercher | ||
* L = liste triée | * L = liste triée | ||
- | * cmp = fonction de comparaison à utiliser (qui doit être la même que celle qui a servi au tri!) | + | * cmp = fonction de comparaison à utiliser (**//qui doit être la même que celle qui a servi au tri!//**) |
* key = fonction de conversion utile à ce qu'on recherche | * key = fonction de conversion utile à ce qu'on recherche | ||
Ligne 528: | Ligne 554: | ||
Avec Python 3.x, on utilise la même formule. | Avec Python 3.x, on utilise la même formule. | ||
+ | |||
+ | ===== Tests de performances ===== | ||
+ | |||
+ | Même si le tri utilisé (sort ou sorted) est très rapide, les fonctions de comparaison sont écrites en Python et analysent les chaines caractère par caractère: est-ce suffisamment rapide? | ||
+ | |||
+ | Pour le vérifier, on va créer des chaines au hasard, et on va compter les temps de tri. | ||
+ | |||
+ | Le nombre de chaines à créer est un paramètre. La longueur de chaque chaine est tirée au hasard entre 10 et 50 caractères. Et chaque caractère est tiré au hasard dans la chaine de référence alpha. Cela donne des chaines bizarres comme %%" | ||
+ | |||
+ | <code python> | ||
+ | from time import clock | ||
+ | |||
+ | alpha = ur""" | ||
+ | u" | ||
+ | u" | ||
+ | u" | ||
+ | lgalpha = len(alpha) | ||
+ | |||
+ | L = [] | ||
+ | n = 1000 | ||
+ | for i in xrange(0, | ||
+ | lg = randint(10, | ||
+ | ch = u"" | ||
+ | for j in xrange(0, | ||
+ | ch += alpha[randint(0, | ||
+ | L.append(ch) | ||
+ | |||
+ | t = clock() | ||
+ | L.sort(cmp=compalphafr) | ||
+ | t = clock()-t | ||
+ | |||
+ | print t | ||
+ | </ | ||
+ | |||
+ | Résultats: | ||
+ | * 1000 chaines à trier: 5/100 seconde | ||
+ | * 10000 chaines à trier: 7/10 seconde | ||
+ | * 100000 chaines à trier: 10 secondes | ||
+ | * 1000000 chaines à trier: 2 minutes | ||
+ | |||
+ | Ce qui n'est pas mal du tout pour du code interprété. | ||
+ | |||
+ | Et pour la recherche dichotomique? | ||
+ | |||
+ | Prenons la dernière liste de 1000000 (un million) de chaines, et voyons le temps nécessaire pour trouver l'une des chaines x dans cette liste: | ||
+ | |||
+ | <code python> | ||
+ | x = L[4999] | ||
+ | t = clock() | ||
+ | r = dichot(x, L, comp=compalphafr, | ||
+ | t = clock()-t | ||
+ | print r | ||
+ | print t | ||
+ | </ | ||
+ | Le résultat correct [0,4999] est trouvé en... 2/10000 seconde! Ça vous suffira comme rapidité? | ||