Lors d’un projet devant exploiter des flux RSS, je me suis rendu compte que malheureusement un grand nombre de flux n’indiquent pas correctement ou pas du tout la langue des articles publiés dans le flux. Selon la norme du RSS 2.0, cette information est en fait optionnelle (sous élément « language » de l’élément « channel »). Ceci peux poser des problèmes pour exploiter au mieux ces flux. Dans mon cas, je devais indexer les flux avec Lucene et offrir des fonctionnalités de recherche dans ces flux et dans les articles qu’ils référençaient. Hors, pour offrir des fonctionnalités de recherche avancées et exploitant au mieux les différents analyseurs linguistiques de Lucene, connaître la langue est impératif.
J’ai donc décidé de mettre en place un module de détection de la langue pour les flux dans lesquels cette information était manquante. Il existe plusieurs algorithmes qui permettent de détecter la langue d’un texte. Une des techniques consiste à analyser le texte et répertorier tous les Ngrams (séquences de n caractères consécutifs) et de compter la fréquence d’apparition de ces Ngrams dans le texte à détecter. Les algorithmes basés sur ce principe compte généralement les fréquences d’apparition de 1-gram, bi-grams ou tri-grams. Par exemple, dans le mot « module », les bi-gram sont : « mo », « od, « du », ul » et « le » et les trim-grams sont : »mod », « odu, « dul » et »ule ».
Il suffit ensuite de comparer le résultat de ce comptage à un référentiel établie au préalable pour chacune des langues sur un corpus de documents. Cette méthode statistique permet d’établir un score d’appartenance du texte à différentes langues. Par exemple, pour un texte, le résultat fournit pourrait être : Allemand : 0,6 – Anglais : 0,33 – Italien : 0,1.
A priori, la langue du texte est celle correspondant au score le plus fort (dans l’exemple, il s’agirait de l’allemand). En fait, il n’y a pas d’algorithme fiable à 100% et les résultats doivent être interprétés avec précaution. On peut par exemple décider que si aucune langue n’a un score supérieur à un seuil minimum ou que si la différence entre le score de la langue 1 et celui de la langue 2 est trop faible, la détection a échouée.
C’est cette solution que j’ai mis en place en Java. Pour cela, j’ai utilisé NgramJ. Il s’agit d’un projet open source disponible sur sourceforge. La mise en oeuvre est très simple et voici un exemple de code permettant de réaliser la détection de la langue du texte contenue dans une chaîne de caractères:
package ...;
import de.spieleck.app.cngram.NGramProfiles;
import java.io.InputStream;
import java.io.ByteArrayInputStream;
import java.io.Reader;
import java.io.InputStreamReader;
public class LanguageRecognizer {
public static String RecognizeLanguage (String text, String encoding)
{
NGramProfiles nps = null;
NGramProfiles.Ranker ranker = null;
try
{
nps = new NGramProfiles();
ranker = nps.getRanker();
if (ranker!=null)
{
if ("".equals(encoding))
encoding = "utf-8";
InputStream inputStream1 = new ByteArrayInputStream(text.getBytes());
Reader reader1 = new InputStreamReader(inputStream1, encoding);
ranker.reset();
ranker.account(reader1);
NGramProfiles.RankResult res = ranker.getRankResult();
String result = res.getName(0);
if (res.getScore(0) < 0.1)
result = "xx";
return result;
}
}
catch (Exception e)
{
return "xx";
}
return "xx";
}
}
Dans cette exemple, si le score le plus élevé est inférieur à 0.1, on considère que la détection a échoué et le code de langue « xx » est retourné en résultat.
Voici un article intéressant sur le sujet : A composite approach to language/encoding detection