Python : ajouter des recherches en expressions régulières à sqlite3
Un billet de blog de tyrtamos
Le 04/03/2015, par tyrtamos, Expert éminent
Problématique
Le SGBDR sqlite3 qui vient avec Python ne comporte pas d'instruction permettant les recherches avec des expressions régulières. Il y a cependant des cas où on en a vraiment besoin. Comme c'est facile à ajouter, on va le faire!
Solution
On va ajouter 2 fonctions:
Fonction regexp
Voilà la 1ère fonction. Il faut, bien sûr, importer le module re avant (=> import re):
On déclare cette fonction dans le pilote sqlite3 de Python comme suit (cnx est la variable de connexion à la base de données):
Cette fonction, bien que non fournie par sqlite3, a cependant prévu une syntaxe particulière. Ainsi, au lieu d'utiliser une syntaxe comme "REGEXP(motif,item)", on va utiliser: "item REGEXP motif"!
Voilà un petit test:
Une table appelée "test" contient un champ "mots" qui contient:
On va chercher avec un script SQL les lignes qui contiennent des parenthèses ("cur" est ici un curseur):
Voilà ce que liste contient:
On voit bien que l'item qui ne contient pas les parenthèses n'a pas été pris en compte.
Fonction regextract
Dans la liste précente qui contient au moins une fois des parenthèses, on va créer une 2ème fonction qui va en extraire son contenu.
Application:
Et cette fois le résultat sera:
Bien sûr, on pourrait ne prendre que le contenu des parenthèses sans celles-ci: il suffit de modifier un peu le motif:
.
Le SGBDR sqlite3 qui vient avec Python ne comporte pas d'instruction permettant les recherches avec des expressions régulières. Il y a cependant des cas où on en a vraiment besoin. Comme c'est facile à ajouter, on va le faire!
Solution
On va ajouter 2 fonctions:
- regexp(motif, item) qui va dire si oui on non l'item satisfait le motif
- regextract(motif, item) qui va retourner la 1ère sous-chaine trouvée qui satisfait le motif, ou None s'il n'y en a pas.
Fonction regexp
Voilà la 1ère fonction. Il faut, bien sûr, importer le module re avant (=> import re):
Code PYTHON : |
1 2 3 4 5 6 | def regexp(motif, item): """retourne True si le motif regex a été satisfait dans l'item False sinon """ regex = re.compile(motif, re.I) # re.I: ignore casse return regex.search(item) is not None |
On déclare cette fonction dans le pilote sqlite3 de Python comme suit (cnx est la variable de connexion à la base de données):
Code PYTHON : |
cnx.create_function("REGEXP", 2, regexp)
Cette fonction, bien que non fournie par sqlite3, a cependant prévu une syntaxe particulière. Ainsi, au lieu d'utiliser une syntaxe comme "REGEXP(motif,item)", on va utiliser: "item REGEXP motif"!
Voilà un petit test:
Une table appelée "test" contient un champ "mots" qui contient:
Code : |
1 2 3 4 5 | aaa bbb ccc(ddd)eee fff aaa (bbb) ccc (aaa)bbb ccc ddd aaabbbcccddd(eee) aaabbbcccddd |
Code PYTHON : |
1 2 3 4 5 6 7 | cur.execute(""" SELECT mots FROM test WHERE mots REGEXP ? ORDER BY mots """, ('\(.*\)',)) liste = cur.fetchall() |
Voilà ce que liste contient:
Code : |
1 2 3 4 | (aaa)bbb ccc ddd aaa (bbb) ccc aaa bbb ccc(ddd)eee fff aaabbbcccddd(eee) |
Fonction regextract
Dans la liste précente qui contient au moins une fois des parenthèses, on va créer une 2ème fonction qui va en extraire son contenu.
Code PYTHON : |
1 2 3 4 5 6 7 8 9 10 | def regextract(motif, item): """retourne la 1ère sous-chaine qui satisfait au motif regex donné si aucune sous-chaine n'est trouvée, renvoie None """ regex = re.compile(motif, re.I) # re.I: ignore la casse result = regex.findall(item) # liste des sous-chaines trouvées if result != []: return result[0] # on ne renvoie que la 1ère s'il y en a plusieurs else: return None |
Application:
Code PYTHON : |
1 2 3 4 5 6 7 | cur.execute(""" SELECT regextract(?,mots) as parentheses FROM test WHERE mots REGEXP ? ORDER BY parentheses """, ('\(.*\)', '\(.*\)')) liste = cur.fetchall() |
Et cette fois le résultat sera:
Code : |
1 2 3 4 | (aaa) (bbb) (ddd) (eee) |
Code : |
'\((.*)\)'