Difference between revisions of "Application lttoolbox"
m (moved Application Lttoolbox to Application lttoolbox) |
|
(No difference)
| |
Revision as of 16:18, 19 February 2013
Vous pouvez utiliser lttoolbox comme bibliothèque en C++ avec #include <lttoolbox/fst_processor.h>, et avec un peu plus de travail, vous pouvez aussi l'utiliser depuis Python.
Contents
Utilisation comme bibliothèque en C++
Pour cet exemple, vous aurez besoin de deux fichiers : test.dix
<dictionary>
<alphabet/>
<sdefs>
<sdef n="n"/>
<sdef n="pl"/>
</sdefs>
<section id="main" type="standard">
<e><p><l>cars</l><r>car<s n="n"/><s n="pl"/></r></p></e>
</section>
</dictionary>
et test.cc.
#include <stdio.h>
#include <string>
#include <iostream>
#include <lttoolbox/fst_processor.h>
#include <lttoolbox/lt_locale.h>
#include <lttoolbox/ltstr.h>
using namespace std;
FSTProcessor fstp;
int main(int argc, char **argv)
{
if(argc < 2) {
wcout << L"Veuillez spécifier un transducteur" << endl;
exit(-1);
}
LtLocale::tryToSetLocale();
FILE *t_rl = fopen(argv[1], "r");
fstp.load(t_rl);
fclose(t_rl);
fstp.initBiltrans();
wstring input = L"^car<n><pl>$";
wstring trad = fstp.biltrans(input);
wcout << entrée << L" --> " << trad << endl;
return 0;
}
Compilez les deux fichiers :
$ lt-comp rl test.dix test_rl.bin main@standard 6 5 $ g++ -Wall test.cc -o test -llttoolbox3
Puis testez :
$ ./test test_rl.bin ^car<n><pl>$ --> ^cars$
Utilisation comme module depuis Python
Cet exemple est basé sur la manière dont libvoikko (a traduire ?) utilise lttoolbox pour l'analyse. On fait une bibliothèque C++ qui expose n'importe quelle fonction lttoolbox dont on a besoin pour Python, et une petite classe Python qui rend l'appel de ces fonctions un peu plus pythonique.[1]
Écrivez les fichiers qui suivent :
libltpy.h:
#include <lttoolbox/fst_processor.h>
class Analyser {
public:
Analyser(const std::string & directoryName) throw(exception);
wstring analyse(wstring const &word);
private:
FSTProcessor fst;
};
libltpy.cc:
#include "libltpy.hpp"
#include <lttoolbox/fst_processor.h>
#include <lttoolbox/lt_locale.h>
using namespace std;
Analyser::Analyser(const string & analyserpath) throw(exception) {
FILE * file = fopen(analyserpath.c_str(), "r");
if (!file) {
cerr << "Impossible d'ouvrir le fichier analyseur " << analyserpath << endl;
throw exception();
}
fst.load(file);
fclose(file);
fst.setCaseSensitiveMode(false);
fst.setDictionaryCaseMode(true);
fst.initBiltrans();
}
wstring Analyser::analyse(wstring const &word) {
pair <wstring,int> analysis = fst.biltransWithQueue(word, false);
// Le 'faux' signifie que les ^ ou $ ne sont pas nécessaires en entrée/sortie
if (analysis.second == 0) {
return analysis.first;
}
else {
// une correspondance partielle :
return L"@"+word;
}
}
extern "C" wstring * analyse(Analyser * a, const wchar_t * word) {
// Il semble que Python peut seulement envoyer des wchar_t*, mais on a besoin d'une wstring
size_t wlen = wcslen(word);
if (wlen == 0) {
// éviter un bug dans biltransWithQueue:
return 0;
}
wstring inputString = L"";
for (size_t i = 0; i < wlen; i++) {
inputString.append(1, word[i]);
}
wstring * out = new wstring(a->analyse(inputString));
return out;
}
EXTERN void free_analyses(wstring * analyses) {
delete analyses;
}
extern "C" Analyser * init(const char ** error, const char * path) {
LtLocale::tryToSetLocale();
Analyser * a = 0;
try {
a = new Analyser(path);
}
catch (exception & e) {
delete a;
a = 0;
*error = e.what();
return 0;
}
*error = 0;
return a;
}
extern "C" void terminate(Analyser * a) {
delete a;
}
lt.py:
# -*- coding: utf-8 -*-
from ctypes import byref, CDLL, c_char_p, c_wchar_p, c_void_p, POINTER
class FST(object):
def __init__(self, libpath, fstpath):
self.__lib = CDLL(libpath)
self.__lib.init.argtypes = [POINTER(c_char_p), c_char_p]
self.__lib.init.restype = c_void_p
self.__lib.terminate.argtypes = [c_void_p]
self.__lib.terminate.restype = None
self.__lib.analyse.argtypes = [c_void_p, c_wchar_p]
self.__lib.analyse.restype = POINTER(c_wchar_p)
error = c_char_p()
self.__handle = self.__lib.init(byref(error), fstpath)
if error.value != None:
self.__handle = 0
raise Exception(u"Erreur d'initialisation de fst : " + unicode(error.value, "UTF-8"))
def __del__(self):
if (self.__handle != 0):
self.__handle = 0
class DummyLib:
def __getattr__(obj, name):
raise Exception("Tentative d'utilisation de la bibliothèque après l'appel de terminate()")
self.__lib = DummyLib()
def analyse(self, word):
ana_p = self.__lib.analyse(self.__handle, word)
if ana_p:
analysis = ana_p.contents.value
else:
analysis = ""
self.__lib.free_analyses(ana_p)
return analysis
Compilez les fichiers C++ afin d'obtenir un fichier comme libltpy.so. Les commandes qui suivent on travaillé pour moi :
g++ -DGCC_VISIBILITY=1 -g -O2 -fvisibility=hidden -I/usr/local/include/lttoolbox-3.2 -I/usr/local/lib/lttoolbox-3.2/include -c libltpy.cpp -fPIC -DPIC -o libltpy.o g++ -fPIC -DPIC -shared libltpy.o -Wl,-rpath -Wl,/usr/local/lib -Wl,-rpath -Wl,/usr/local/lib -L/usr/local/lib /usr/local/lib/liblttoolbox3.so -Wl,-soname -Wl,libltpy.so.0 -o libltpy.so
Quoi qu'il en soit, si vous utilisez des outils automatiques, vous avez pratiquement juste besoin de ce qui suit dans votre Makefile.am :
lib_LTLIBRARIES = libltpy.la libltpy_la_SOURCES = libltpy.cpp libltpy_la_LDFLAGS = $(LTTOOLBOX_LIBS)
ensuite autogen.sh et make libltpy.la (voir #Exemples sur des mots réels).
Alors utilisez-le comme :
import lt
fst = lt.FST("libltpy.so", "analyser.bin")
print fst.analyse(u"cars") # devrait afficher car<n><pl>
Exemples sur des mots réels
- apertium-transfer utilise lttoolbox depuis le C++ pour examiner des mots dans le bidix
- libvoikko utilise lttoolbox depuis le C++ pour analyser des mots, et aussi fabrique un module Python :
Notes
- ↑ Une alternative pourrait être d'inclure Python.h dans le code C++, et définir une classe Python complète à partir de là, à la manière dont pylibtextcat/py3libtextcat crée une classe Python pour la bibliothèque C.