package fr.openwide.core.jpa.search.analysis.fr;
/**
* Stemmer adapté depuis le FrenchMinimalStemmer qui a les particularités
* suivantes :
* - on ne désactive le stemming que si la chaîne fait moins de 4
* caractères et pas 6 (typiquement, problème sur stage et stages, noir et noire)
* - on enlève la suppression des doublements de lettres en fin de mot pour éviter marmot == marmotte
* - on arrête le stemming si le mot devient trop court de manière à éviter le phénomène stage/stages sur des mots
* très courts
*/
public class CoreFrenchMinimalStemmer {
/**
* on analyse les mots dès qu'ils font plus de tant de caractères
*
* /!\ certaines règles dépendent de ce choix de longueur : il faut donc faire attention à ne pas le descendre
* ou alors il faut intégrer des checks en plus ci-dessous quand on remonte dans les index
*/
private static final int MIN_LENGTH_HARD_LIMIT = 5;
private static final int MIN_LENGTH_PLURAL_LIMIT = 4;
public int stem(char s[], int len) {
if (len < MIN_LENGTH_HARD_LIMIT) {
if (len >= MIN_LENGTH_PLURAL_LIMIT) {
return stemLetter(s, len, 's', MIN_LENGTH_PLURAL_LIMIT);
}
return len;
}
if (s[len - 1] == 'x') {
if (s[len - 3] == 'a' && s[len - 2] == 'u' && s[len -4] != 'e') {
s[len - 2] = 'l';
}
return len - 1;
}
int refLen = len;
len = stemLetter(s, len, 's');
if (len == refLen) {
// on ne s'attaque au r que s'il n'y a pas eu remplacement avant
len = stemLetterIfPreviousLetterIs(s, len, 'r', 'e');
}
len = stemLetter(s, len, 'e');
len = stemLetter(s, len, 'é');
return len;
}
private int stemLetter(char s[], int len, char letter) {
return stemLetter(s, len, letter, MIN_LENGTH_HARD_LIMIT);
}
private int stemLetter(char s[], int len, char letter, int limit) {
if (len >= limit && s[len - 1] == letter) {
return len - 1;
}
return len;
}
private int stemLetterIfPreviousLetterIs(char s[], int len, char letter, char previousLetter) {
if (len >= MIN_LENGTH_HARD_LIMIT && s[len - 1] == letter) {
return len - 1;
}
return len;
}
}