Commit | Line | Data |
---|---|---|
4dabedd6 P |
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% ! | |
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 | outbuf = create_string_buffer(4096) | |
60 | outbytesleft = c_size_t(len(outbuf)) | |
61 | ||
62 | # on effectue la conversion | |
63 | _iconv(cp, byref(pointer(inbuf)), byref(inbytesleft), | |
64 | byref(pointer(outbuf)), byref(outbytesleft)) | |
65 | result = outbuf.value[:outbytesleft.value] | |
66 | ||
67 | # on détruit le contexte de conversion et on retourne le résultat | |
68 | _iconv_close(cp) | |
69 | return result | |
70 | ||
71 | if __name__ == "__main__": | |
72 | # on précise la translitération via un environnement linguistique | |
73 | from locale import setlocale, LC_ALL | |
74 | setlocale(LC_ALL, 'en_US.UTF-8') | |
75 | ||
76 | # test de cas limites (en français, vietnamien et japonais) | |
77 | from unicodedata import normalize | |
78 | t = u"fête cœur français tiếng việt đường プログフ" | |
79 | i = iconv("utf-8", "ascii//TRANSLIT", t.encode('utf-8')) | |
80 | u = normalize("NFKD", t).encode('ascii','ignore') | |
81 | print u"TEST: texte original: '%s'" % t | |
82 | print u"TEST: iconv(utf8..ascii//TRANSLIT): '%s'" % i | |
83 | print u"TEST: normalize(NFKD).encode(ascii,ignore): '%s'" % u | |
84 |