Cette page présente un petit exemple de liaison entre Python et une librairie dynamique en C.
L'exemple choisi ici est l'implémentation d'un appel depuis Python à la fonction iconv de la librairie C.
Documentation utilisée : http://docs.python.org/library/ctypes.html
Fichier /usr/local/lib/python2.5/site-packages/iconv.py :
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 """
4 Module de support iconv pour Python.
5
6 Copyright : Agence universitaire de la Francophonie
7 Licence : GNU General Public Licence, version 2
8 Auteur : Jean Christophe André
9 Date de création : 20 mars 2009
10 """
11
12 from ctypes import *
13 from ctypes.util import find_library
14
15 # on n'exporte que la fonction iconv ('a marche pô ?!)
16 __all__ = ["iconv"]
17
18 # la librairie C
19 _libc = CDLL(find_library("c"))
20
21 # un type spécifique à iconv (pour stoquer l'état de son automate)
22 _iconv_t = c_void_p
23
24 # prototype de la fonction iconv_open(3)
25 _iconv_open = _libc.iconv_open
26 _iconv_open.argtypes = [c_char_p, c_char_p]
27 _iconv_open.restype = _iconv_t
28
29 # prototype de la fonction iconv(3)
30 _iconv = _libc.iconv
31 _iconv.argtypes = [_iconv_t,
32 POINTER(POINTER(ARRAY(c_char, 1024))), POINTER(c_size_t),
33 POINTER(POINTER(ARRAY(c_char, 4096))), POINTER(c_size_t)]
34 _iconv.restype = c_size_t
35
36 # prototype de la fonction iconv_close(3)
37 _iconv_close = _libc.iconv_close
38 _iconv_close.argtypes = [_iconv_t]
39 _iconv_close.restype = c_int
40
41 def iconv(from_code, to_code, string):
42 """
43 from_code : encodage d'origine de string
44 to_code : encodage souhaité en retour
45 string : la chaîne dont il faut convertir l'encodage
46
47 On pourra utiliser to_code='ascii//TRANSLIT' pour supprimer les accents.
48 Attention : ça ne fonctionne pas à 100% avec les langues hors Latin-{N} !
49
50 Plus de détails dans la page de manuel de iconv(1).
51 """
52
53 # on commence par créer un contexte de conversion
54 cp = _iconv_open(c_char_p(to_code), c_char_p(from_code))
55
56 # on prépare les structures de données à transmettres
57 inbuf = create_string_buffer(string, 1024)
58 inbytesleft = c_size_t(len(inbuf))
59 p_inbuf = pointer(inbuf)
60 outbuf = create_string_buffer(4096)
61 outbytesleft = c_size_t(len(outbuf))
62 p_outbuf = pointer(outbuf)
63
64 # on effectue la conversion
65 _iconv(cp, byref(p_inbuf), byref(inbytesleft),
66 byref(p_outbuf), byref(outbytesleft))
67 result = outbuf.value[:outbytesleft.value]
68
69 # on détruit le contexte de conversion et on retourne le résultat
70 _iconv_close(cp)
71 return result
72
73 if __name__ == "__main__":
74 # on précise la translitération via un environnement linguistique
75 from locale import setlocale, LC_ALL
76 setlocale(LC_ALL, 'en_US.UTF-8')
77
78 # test de cas limites (en français, vietnamien et japonais)
79 from unicodedata import normalize
80 t = u"fête cœur français tiếng việt đường プログフ"
81 i = iconv("utf-8", "ascii//TRANSLIT", t.encode('utf-8'))
82 u = normalize("NFKD", t).encode('ascii','ignore')
83 print u"TEST: texte original: '%s'" % t
84 print u"TEST: iconv(utf8..ascii//TRANSLIT): '%s'" % i
85 print u"TEST: normalize(NFKD).encode(ascii,ignore): '%s'" % u
Lancement d'un test :
python /usr/local/lib/python2.5/site-packages/iconv.py
Résultat sur Ubuntu "Intrepid" 8.10 :
$ python iconv.py TEST: texte original: 'fête cœur français tiếng việt đường プログフ' TEST: iconv(utf8..ascii//TRANSLIT): 'fete coeur francais tieng viet ?uong ????' TEST: normalize(NFKD).encode(ascii,ignore): 'fete cur francais tieng viet uong '
Exemple d'utilisation dans un programme :
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 from iconv import iconv
5 from locale import setlocale,LC_ALL
6
7 setlocale(LC_ALL, 'fr_FR.UTF-8')
8
9 texte_utf8 = u"fête cœur français".encode("utf-8")
10 texte_sans_accent = iconv("utf-8", "ascii//TRANSLIT", texte_utf8)
11
12 print u"Texte d'origine :", texte_utf8
13 print u"Suppression des accents :", texte_sans_accent