View Javadoc
1   package org.andromda.utils.inflector;
2   
3   import java.util.ArrayList;
4   import java.util.List;
5   import java.util.regex.Matcher;
6   import java.util.regex.Pattern;
7   
8   /**
9    * Language utility for transforming French words
10   *
11   * @author Cédric Vidal
12   */
13  public class FrenchInflector
14  {
15      private static final List<Inflection> plurals = new ArrayList<Inflection>();
16  
17      private static final List<Pattern> uncountables = new ArrayList<Pattern>();
18  
19      /**
20       *
21       */
22      static class Inflection
23      {
24          private final Pattern pattern;
25  
26          private final String replace;
27  
28          /**
29           * @param pattern
30           * @param replace
31           */
32          public Inflection(Pattern pattern, String replace)
33          {
34              super();
35              this.pattern = pattern;
36              this.replace = replace;
37          }
38  
39          /**
40           * @param regexp
41           * @param replace
42           */
43          public Inflection(String regexp, String replace)
44          {
45              super();
46              this.pattern = Pattern.compile(regexp);
47              this.replace = replace;
48          }
49  
50          /**
51           * @return pattern
52           */
53          public Pattern getPattern()
54          {
55              return pattern;
56          }
57  
58          /**
59           * @return replace
60           */
61          public String getReplace()
62          {
63              return replace;
64          }
65      }
66  
67      static
68      {
69          /*
70           * NON COMPOSED WORDS
71           */
72  
73          uncountable(endsWith("(s|x|z)"));
74  
75          /*
76           * -al words such as cheval -> chevaux (horse)
77           */
78          takeAnS(new String[]{"bal", "carnaval", "c?r?monial", "chacal",
79              "choral", "festival", "nopal", "pal", "r?cital", "r?gal",
80              "santal"});
81          plural(endsWith("(al)"), "$1aux");
82  
83          /*
84           * -eau words such as rideau -> rideaux (curtain) -eu words such as ?meu ->
85           * ?meux (the bird)
86           */
87          takeAnS(new String[]{"landau", "sarrau", "bleu", "?meu", "emposieu",
88              "enfeu", "feu" /* adj */, "lieu" /* le poisson */, "pneu",
89              "richelieu", "schleu"});
90          plural(endsWith("(au|eu|eau)"), "$1$2x");
91  
92          /*
93           * -ou words take an s except the following exceptions
94           */
95          takeAnX(new String[]{"bijou", "caillou", "chou", "genou", "hibou",
96              "joujou", "pou"});
97  
98          /*
99           * -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 }