Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Python : faire du tri selon le dictionnaire français avec sqlite3
Un billet de blog de tyrtamos

Le , par tyrtamos

0PARTAGES

Problématique

Quand on veut extraire d'une base SQL des informations texte triées en utilisant 'ORDER BY', on se heurte au problème habituel: l'ordre de tri coïncide avec l'ordre des caractères dans les polices de caractères, c'est à dire, par exemple, que:
  • 'a' est situé après 'X' (les minuscules sont situées après les majuscules),
  • 'à' est situé après 'x' (les caractères accentués sont situés après les caractères non accentués).

Solution

Pour trier selon l'alphabet français, et en fait, selon l'alphabet qu'on veut, on va créer une fonction de comparaison comme cmp(v1, v2), c'est à dire qui compare v1 et v2 et qui renvoie:
  • un entier <0 si v1
  • 0 si v1==v2
  • un entier >0 si v1>v2



Ceci, comme on peut le faire avec la méthode sort() du Python.

Voilà le code proposé (Python 3):

Code PYTHON : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import locale 
  
class Compdicofr(object): 
    """comparaison de 2 chaines selon le dictionnaire français""" 
  
    def __init__(self): 
        self.loc = locale.getlocale()  # stocke la locale courante 
        self.espinsec = '\xA0'  # espace insécable 
  
    def __call__(self, v1, v2): 
  
        # on retire les tirets et les blancs insécables 
        v1 = v1.replace('-', '') 
        v1 = v1.replace(self.espinsec, '') 
        v2 = v2.replace('-', '') 
        v2 = v2.replace(self.espinsec, '') 
  
        # on fait la comparaison selon la locale 
        locale.setlocale(locale.LC_ALL, '') 
        comp = locale.strcoll(v1, v2) 
  
        # retour à la locale initiale 
        locale.setlocale(locale.LC_ALL, self.loc) 
  
        # on retourne le résultat de la comparaison 
        return comp 
  
compdicofr = Compdicofr()

Prenons maintenant un exemple: on crée une base sqlite3 contenant une table "test" avec un champ "mots" contenant dans l'ordre d'introduction:

Code : Sélectionner tout
1
2
3
4
5
6
xabc 
abcç 
abcé 
Xabcù 
Abcè 
êqsdf
Voilà le code pour extraire ces données et les présenter dans l'ordre de tri habituel:

Code PYTHON : Sélectionner tout
1
2
3
4
5
6
7
8
9
cur.execute(""" 
    SELECT * 
    FROM test  
    ORDER BY mots 
    """) 
datas = cur.fetchall() 
  
for data in datas: 
    print data[0]

Ce qui donne à l'exécution:

Code : Sélectionner tout
1
2
3
4
5
6
Abcè 
Xabcù 
abcç 
abcé 
xabc 
êqsdf
Vous constatez que ce n'est pas terrible: le 'a' est après le 'X' et le 'ê' est après le 'x'...

Voilà maintenant le code qui permet de trier dans le bon ordre:

Code PYTHON : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
cnx.create_collation("compdicofr", compdicofr) 
  
cur.execute(""" 
    SELECT * 
    FROM test  
    ORDER BY mots COLLATE compdicofr 
    """) 
datas = cur.fetchall() 
  
for data in datas: 
    print data[0]

Ce qui affiche:

Code : Sélectionner tout
1
2
3
4
5
6
abcç 
abcé 
Abcè 
êqsdf 
xabc 
Xabcù
C'est quand même autre chose, non?

Une erreur dans cette actualité ? Signalez-le nous !