001package org.andromda.utils.inflector; 002 003import java.util.ArrayList; 004import java.util.List; 005import java.util.regex.Matcher; 006import java.util.regex.Pattern; 007 008/** 009 * Language utility for transforming French words 010 * 011 * @author Cédric Vidal 012 */ 013public class FrenchInflector 014{ 015 private static final List<Inflection> plurals = new ArrayList<Inflection>(); 016 017 private static final List<Pattern> uncountables = new ArrayList<Pattern>(); 018 019 /** 020 * 021 */ 022 static class Inflection 023 { 024 private final Pattern pattern; 025 026 private final String replace; 027 028 /** 029 * @param pattern 030 * @param replace 031 */ 032 public Inflection(Pattern pattern, String replace) 033 { 034 super(); 035 this.pattern = pattern; 036 this.replace = replace; 037 } 038 039 /** 040 * @param regexp 041 * @param replace 042 */ 043 public Inflection(String regexp, String replace) 044 { 045 super(); 046 this.pattern = Pattern.compile(regexp); 047 this.replace = replace; 048 } 049 050 /** 051 * @return pattern 052 */ 053 public Pattern getPattern() 054 { 055 return pattern; 056 } 057 058 /** 059 * @return replace 060 */ 061 public String getReplace() 062 { 063 return replace; 064 } 065 } 066 067 static 068 { 069 /* 070 * NON COMPOSED WORDS 071 */ 072 073 uncountable(endsWith("(s|x|z)")); 074 075 /* 076 * -al words such as cheval -> chevaux (horse) 077 */ 078 takeAnS(new String[]{"bal", "carnaval", "c?r?monial", "chacal", 079 "choral", "festival", "nopal", "pal", "r?cital", "r?gal", 080 "santal"}); 081 plural(endsWith("(al)"), "$1aux"); 082 083 /* 084 * -eau words such as rideau -> rideaux (curtain) -eu words such as ?meu -> 085 * ?meux (the bird) 086 */ 087 takeAnS(new String[]{"landau", "sarrau", "bleu", "?meu", "emposieu", 088 "enfeu", "feu" /* adj */, "lieu" /* le poisson */, "pneu", 089 "richelieu", "schleu"}); 090 plural(endsWith("(au|eu|eau)"), "$1$2x"); 091 092 /* 093 * -ou words take an s except the following exceptions 094 */ 095 takeAnX(new String[]{"bijou", "caillou", "chou", "genou", "hibou", 096 "joujou", "pou"}); 097 098 /* 099 * -ail words take an S suche as portail -> portails except the 100 * following exceptions 101 */ 102 ailIrregulars(new String[]{"b", "cor", "?m", "soupir", "trav", 103 "vant", "vitr"}); 104 105 /* 106 * Exceptions that doesn't fall in any category 107 */ 108 plural(endsWith("a?eul"), "$1a?eux"); 109 plural(endsWith("ciel"), "$1cieux"); 110 plural(endsWith("oeil"), "$1yeux"); 111 112 /* 113 * COMPOSED WORDS Remains to be done. Requires type information only 114 * available from a dictionary 115 */ 116 } 117 118 /** 119 * Add a pattern that if matched return the original word 120 * 121 * @param pattern 122 */ 123 private static void uncountable(String pattern) 124 { 125 uncountables.add(Pattern.compile(pattern)); 126 } 127 128 /** 129 * -ail words that don't follow the rule 130 * 131 * @param strings 132 */ 133 private static void ailIrregulars(String[] strings) 134 { 135 for (String string : strings) 136 { 137 plural("(\\S*)" + string + "ail$", "$1" + string + "aux"); 138 } 139 } 140 141 /** 142 * Words that take an S 143 * 144 * @param patterns 145 */ 146 private static void takeAnS(String[] patterns) 147 { 148 for (String string : patterns) 149 { 150 plural(endsWith(string), "$1" + string + 's'); 151 } 152 } 153 154 /** 155 * Words that take an X 156 * 157 * @param patterns 158 */ 159 private static void takeAnX(String[] patterns) 160 { 161 for (String string : patterns) 162 { 163 plural(endsWith(string), "$1" + string + 'x'); 164 } 165 } 166 167 /** 168 * More complex pluralizations 169 * 170 * @param pattern 171 * @param replace 172 */ 173 private static void plural(String pattern, String replace) 174 { 175 plurals.add(new Inflection(pattern, replace)); 176 } 177 178 /** 179 * @param end 180 * @return a pattern that matches words ending with the given parameter 181 */ 182 private static String endsWith(String end) 183 { 184 return "(\\S*)" + end + '$'; 185 } 186 187 /** 188 * Converts an French word to plural form 189 * 190 * @param str 191 * @return plural form 192 */ 193 public static String pluralize(String str) 194 { 195 196 for (Pattern pattern : uncountables) 197 { 198 Matcher matcher = pattern.matcher(str); 199 if (matcher.matches()) 200 { 201 return str; 202 } 203 } 204 205 List<Inflection> rules = FrenchInflector.getPluralRules(); 206 for (Inflection inflection : rules) 207 { 208 Pattern pattern = inflection.getPattern(); 209 String replace = inflection.getReplace(); 210 Matcher matcher = pattern.matcher(str); 211 if (matcher.matches()) 212 { 213 return matcher.replaceFirst(replace); 214 } 215 } 216 return str.replaceFirst("([\\w]+)([^s])$", "$1$2s"); 217 } 218 219 /** 220 * Returns map of plural patterns 221 */ 222 private static List<Inflection> getPluralRules() 223 { 224 return plurals; 225 } 226}