001/* 002 * Copyright 2011 Atteo. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 005 * in compliance with the License. You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software distributed under the License 010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 011 * or implied. See the License for the specific language governing permissions and limitations under 012 * the License. 013 */ 014package org.atteo.evo.inflector; 015 016import java.util.ArrayList; 017import java.util.List; 018import java.util.regex.Matcher; 019import java.util.regex.Pattern; 020 021public abstract class TwoFormInflector { 022 private interface Rule { 023 String getPlural(String singular); 024 } 025 026 private static class RegExpRule implements Rule { 027 private final Pattern singular; 028 private final String plural; 029 030 private RegExpRule(Pattern singular, String plural) { 031 this.singular = singular; 032 this.plural = plural; 033 } 034 035 @Override 036 public String getPlural(String word) { 037 StringBuffer buffer = new StringBuffer(); 038 Matcher matcher = singular.matcher(word); 039 if (matcher.find()) { 040 matcher.appendReplacement(buffer, plural); 041 matcher.appendTail(buffer); 042 return buffer.toString(); 043 } 044 return null; 045 } 046 } 047 048 private static class CategoryRule implements Rule { 049 private final String[] list; 050 private final String singular; 051 private final String plural; 052 053 public CategoryRule(String[] list, String singular, String plural) { 054 this.list = list; 055 this.singular = singular; 056 this.plural = plural; 057 } 058 059 @Override 060 public String getPlural(String word) { 061 String lowerWord = word.toLowerCase(); 062 for (String suffix : list) { 063 if (lowerWord.endsWith(suffix)) { 064 if (!lowerWord.endsWith(singular)) { 065 throw new RuntimeException("Internal error"); 066 } 067 return word.substring(0, word.length() - singular.length()) + plural; 068 } 069 } 070 return null; 071 } 072 } 073 074 private final List<Rule> rules = new ArrayList<Rule>(); 075 076 protected String getPlural(String word) { 077 for (Rule rule : rules) { 078 String result = rule.getPlural(word); 079 if (result != null) { 080 return result; 081 } 082 } 083 return null; 084 } 085 086 protected void uncountable(String[] list) { 087 rules.add(new CategoryRule(list, "", "")); 088 } 089 090 protected void irregular(String singular, String plural) { 091 if (singular.charAt(0) == plural.charAt(0)) { 092 rules.add(new RegExpRule(Pattern.compile("(?i)(" + singular.charAt(0) + ")" + singular.substring(1) 093 + "$"), "$1" + plural.substring(1))); 094 } else { 095 rules.add(new RegExpRule(Pattern.compile(Character.toUpperCase(singular.charAt(0)) + "(?i)" 096 + singular.substring(1) + "$"), Character.toUpperCase(plural.charAt(0)) 097 + plural.substring(1))); 098 rules.add(new RegExpRule(Pattern.compile(Character.toLowerCase(singular.charAt(0)) + "(?i)" 099 + singular.substring(1) + "$"), Character.toLowerCase(plural.charAt(0)) 100 + plural.substring(1))); 101 } 102 } 103 104 protected void irregular(String[][] list) { 105 for (String[] pair : list) { 106 irregular(pair[0], pair[1]); 107 } 108 } 109 110 protected void rule(String singular, String plural) { 111 rules.add(new RegExpRule(Pattern.compile(singular, Pattern.CASE_INSENSITIVE), plural)); 112 } 113 114 protected void rule(String[][] list) { 115 for (String[] pair : list) { 116 rules.add(new RegExpRule(Pattern.compile(pair[0], Pattern.CASE_INSENSITIVE), pair[1])); 117 } 118 } 119 120 protected void categoryRule(String[] list, String singular, String plural) { 121 rules.add(new CategoryRule(list, singular, plural)); 122 } 123}