import java.util.HashSet; import java.util.LinkedList; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Transforms words to singular, plural, humanized (human readable), underscore, camel case, or ordinal form. This is inspired by * the Inflector class in Ruby on Rails, which is distributed under the Rails license. * @author Randall Hauch * */ public class Inflector { protected static final Inflector INSTANCE = new Inflector(); public static final Inflector getInstance() { return INSTANCE; } protected class Rule { protected final String expression; protected final Pattern expressionPattern; protected final String replacement; protected Rule(String expression, String replacement) { this.expression = expression; this.replacement = replacement != null ? replacement : ""; this.expressionPattern = Pattern.compile(this.expression, Pattern.CASE_INSENSITIVE); } /** * Apply the rule against the input string, returning the modified string or null if the rule didn't apply (and no * modifications were made) * * @param input the input string * @return the modified string if this rule applied, or null if the input was not modified by this rule */ protected String apply(String input) { Matcher matcher = this.expressionPattern.matcher(input); if (!matcher.find()) { return null; } return matcher.replaceAll(this.replacement); } @Override public int hashCode() { return expression.hashCode(); } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj != null && obj.getClass() == this.getClass()) { final Rule that = (Rule)obj; if (this.expression.equalsIgnoreCase(that.expression)) { return true; } } return false; } @Override public String toString() { return expression + ", " + replacement; } } private LinkedListplurals = new LinkedList (); private LinkedList singulars = new LinkedList (); /** * The lowercase words that are to be excluded and not processed. This map can be modified by the users via * {@link #getUncountables()}. */ private final Set uncountables = new HashSet (); public Inflector() { initialize(); } protected Inflector(Inflector original) { this.plurals.addAll(original.plurals); this.singulars.addAll(original.singulars); this.uncountables.addAll(original.uncountables); } @Override public Inflector clone() { return new Inflector(this); } // ------------------------------------------------------------------------------------------------ // Usage functions // ------------------------------------------------------------------------------------------------ /** * Returns the plural form of the word in the string. * * Examples: * * * inflector.pluralize("post") #=> "posts" * inflector.pluralize("octopus") #=> "octopi" * inflector.pluralize("sheep") #=> "sheep" * inflector.pluralize("words") #=> "words" * inflector.pluralize("the blue mailman") #=> "the blue mailmen" * inflector.pluralize("CamelOctopus") #=> "CamelOctopi" ** * * * Note that if the {@link Object#toString()} is called on the supplied object, so this method works for non-strings, too. * * * @param word the word that is to be pluralized. * @return the pluralized form of the word, or the word itself if it could not be pluralized * @see #singularize(Object) */ public String pluralize(Object word) { if (word == null) { return null; } String wordStr = word.toString().trim(); if (wordStr.length() == 0) { return wordStr; } if (isUncountable(wordStr)) { return wordStr; } for (Rule rule : this.plurals) { String result = rule.apply(wordStr); if (result != null) { return result; } } return wordStr; } public String pluralize(Object word, int count) { if (word == null) { return null; } if (count == 1 || count == -1) { return word.toString(); } return pluralize(word); } /** * Returns the singular form of the word in the string. * * Examples: * ** inflector.singularize("posts") #=> "post" * inflector.singularize("octopi") #=> "octopus" * inflector.singularize("sheep") #=> "sheep" * inflector.singularize("words") #=> "word" * inflector.singularize("the blue mailmen") #=> "the blue mailman" * inflector.singularize("CamelOctopi") #=> "CamelOctopus" ** * * * Note that if the {@link Object#toString()} is called on the supplied object, so this method works for non-strings, too. * * * @param word the word that is to be pluralized. * @return the pluralized form of the word, or the word itself if it could not be pluralized * @see #pluralize(Object) */ public String singularize(Object word) { if (word == null) { return null; } String wordStr = word.toString().trim(); if (wordStr.length() == 0) { return wordStr; } if (isUncountable(wordStr)) { return wordStr; } for (Rule rule : this.singulars) { String result = rule.apply(wordStr); if (result != null) { return result; } } return wordStr; } /** * Converts strings to lowerCamelCase. This method will also use any extra delimiter characters to identify word boundaries. * * Examples: * ** inflector.lowerCamelCase("active_record") #=> "activeRecord" * inflector.lowerCamelCase("first_name") #=> "firstName" * inflector.lowerCamelCase("name") #=> "name" * inflector.lowerCamelCase("the-first_name",'-') #=> "theFirstName" ** * * * @param lowerCaseAndUnderscoredWord the word that is to be converted to camel case * @param delimiterChars optional characters that are used to delimit word boundaries * @return the lower camel case version of the word * @see #underscore(String, char[]) * @see #camelCase(String, boolean, char[]) * @see #upperCamelCase(String, char[]) */ public String lowerCamelCase(String lowerCaseAndUnderscoredWord, char... delimiterChars) { return camelCase(lowerCaseAndUnderscoredWord, false, delimiterChars); } /** * Converts strings to UpperCamelCase. This method will also use any extra delimiter characters to identify word boundaries. * * Examples: * ** inflector.upperCamelCase("active_record") #=> "SctiveRecord" * inflector.upperCamelCase("first_name") #=> "FirstName" * inflector.upperCamelCase("name") #=> "Name" * inflector.lowerCamelCase("the-first_name",'-') #=> "TheFirstName" ** * * * @param lowerCaseAndUnderscoredWord the word that is to be converted to camel case * @param delimiterChars optional characters that are used to delimit word boundaries * @return the upper camel case version of the word * @see #underscore(String, char[]) * @see #camelCase(String, boolean, char[]) * @see #lowerCamelCase(String, char[]) */ public String upperCamelCase(String lowerCaseAndUnderscoredWord, char... delimiterChars) { return camelCase(lowerCaseAndUnderscoredWord, true, delimiterChars); } /** * By default, this method converts strings to UpperCamelCase. If theuppercaseFirstLetter
argument to false, * then this method produces lowerCamelCase. This method will also use any extra delimiter characters to identify word * boundaries. * * Examples: * ** inflector.camelCase("active_record",false) #=> "activeRecord" * inflector.camelCase("active_record",true) #=> "ActiveRecord" * inflector.camelCase("first_name",false) #=> "firstName" * inflector.camelCase("first_name",true) #=> "FirstName" * inflector.camelCase("name",false) #=> "name" * inflector.camelCase("name",true) #=> "Name" ** * * * @param lowerCaseAndUnderscoredWord the word that is to be converted to camel case * @param uppercaseFirstLetter true if the first character is to be uppercased, or false if the first character is to be * lowercased * @param delimiterChars optional characters that are used to delimit word boundaries * @return the camel case version of the word * @see #underscore(String, char[]) * @see #upperCamelCase(String, char[]) * @see #lowerCamelCase(String, char[]) */ public String camelCase(String lowerCaseAndUnderscoredWord, boolean uppercaseFirstLetter, char... delimiterChars) { if (lowerCaseAndUnderscoredWord == null) { return null; } lowerCaseAndUnderscoredWord = lowerCaseAndUnderscoredWord.trim(); if (lowerCaseAndUnderscoredWord.length() == 0) { return ""; } if (uppercaseFirstLetter) { String result = lowerCaseAndUnderscoredWord; // Replace any extra delimiters with underscores (before the underscores are converted in the next step)... if (delimiterChars != null) { for (char delimiterChar : delimiterChars) { result = result.replace(delimiterChar, '_'); } } // Change the case at the beginning at after each underscore ... return replaceAllWithUppercase(result, "(^|_)(.)", 2); } if (lowerCaseAndUnderscoredWord.length() < 2) { return lowerCaseAndUnderscoredWord; } return "" + Character.toLowerCase(lowerCaseAndUnderscoredWord.charAt(0)) + camelCase(lowerCaseAndUnderscoredWord, true, delimiterChars).substring( 1); } /** * Makes an underscored form from the expression in the string (the reverse of the {@link #camelCase(String, boolean, char[]) * camelCase} method. Also changes any characters that match the supplied delimiters into underscore. * * Examples: * ** inflector.underscore("activeRecord") #=> "active_record" * inflector.underscore("ActiveRecord") #=> "active_record" * inflector.underscore("firstName") #=> "first_name" * inflector.underscore("FirstName") #=> "first_name" * inflector.underscore("name") #=> "name" * inflector.underscore("The.firstName") #=> "the_first_name" ** * * * @param camelCaseWord the camel-cased word that is to be converted; * @param delimiterChars optional characters that are used to delimit word boundaries (beyond capitalization) * @return a lower-cased version of the input, with separate words delimited by the underscore character. */ public String underscore(String camelCaseWord, char... delimiterChars) { if (camelCaseWord == null) { return null; } String result = camelCaseWord.trim(); if (result.length() == 0) { return ""; } result = result.replaceAll("([A-Z]+)([A-Z][a-z])", "$1_$2"); result = result.replaceAll("([a-z\\d])([A-Z])", "$1_$2"); result = result.replace('-', '_'); if (delimiterChars != null) { for (char delimiterChar : delimiterChars) { result = result.replace(delimiterChar, '_'); } } return result.toLowerCase(); } /** * Returns a copy of the input with the first character converted to uppercase and the remainder to lowercase. * * @param words the word to be capitalized * @return the string with the first character capitalized and the remaining characters lowercased */ public String capitalize(String words) { if (words == null) { return null; } String result = words.trim(); if (result.length() == 0) { return ""; } if (result.length() == 1) { return result.toUpperCase(); } return "" + Character.toUpperCase(result.charAt(0)) + result.substring(1). toLowerCase(); } /** * Capitalizes the first word and turns underscores into spaces and strips trailing "_id" and any supplied removable tokens. * Like {@link #titleCase(String, String[])}, this is meant for creating pretty output. * * Examples: * ** inflector.humanize("employee_salary") #=> "Employee salary" * inflector.humanize("author_id") #=> "Author" ** * * * @param lowerCaseAndUnderscoredWords the input to be humanized * @param removableTokens optional array of tokens that are to be removed * @return the humanized string * @see #titleCase(String, String[]) */ public String humanize(String lowerCaseAndUnderscoredWords, String... removableTokens) { if (lowerCaseAndUnderscoredWords == null) { return null; } String result = lowerCaseAndUnderscoredWords.trim(); if (result.length() == 0) { return ""; } // Remove a trailing "_id" token result = result.replaceAll("_id$", ""); // Remove all of the tokens that should be removed if (removableTokens != null) { for (String removableToken : removableTokens) { result = result.replaceAll(removableToken, ""); } } result = result.replaceAll("_+", " "); // replace all adjacent underscores with a single space return capitalize(result); } /** * Capitalizes all the words and replaces some characters in the string to create a nicer looking title. Underscores are * changed to spaces, a trailing "_id" is removed, and any of the supplied tokens are removed. Like * {@link #humanize(String, String[])}, this is meant for creating pretty output. * * Examples: * ** inflector.titleCase("man from the boondocks") #=> "Man From The Boondocks" * inflector.titleCase("x-men: the last stand") #=> "X Men: The Last Stand" ** * * * @param words the input to be turned into title case * @param removableTokens optional array of tokens that are to be removed * @return the title-case version of the supplied words */ public String titleCase(String words, String... removableTokens) { String result = humanize(words, removableTokens); result = replaceAllWithUppercase(result, "\\b([a-z])", 1); // change first char of each word to uppercase return result; } /** * Turns a non-negative number into an ordinal string used to denote the position in an ordered sequence, such as 1st, 2nd, * 3rd, 4th. * * @param number the non-negative number * @return the string with the number and ordinal suffix */ public String ordinalize(int number) { int remainder = number % 100; String numberStr = Integer.toString(number); if (11 <= number && number <= 13) { return numberStr + "th"; } remainder = number % 10; if (remainder == 1) { return numberStr + "st"; } if (remainder == 2) { return numberStr + "nd"; } if (remainder == 3) { return numberStr + "rd"; } return numberStr + "th"; } // ------------------------------------------------------------------------------------------------ // Management methods // ------------------------------------------------------------------------------------------------ /** * Determine whether the supplied word is considered uncountable by the {@link #pluralize(Object) pluralize} and * {@link #singularize(Object) singularize} methods. * * @param word the word * @return true if the plural and singular forms of the word are the same */ public boolean isUncountable(String word) { if (word == null) { return false; } String trimmedLower = word.trim().toLowerCase(); return this.uncountables.contains(trimmedLower); } /** * Get the set of words that are not processed by the Inflector. The resulting map is directly modifiable. * * @return the set of uncountable words */ public SetgetUncountables() { return uncountables; } public void addPluralize(String rule, String replacement) { final Rule pluralizeRule = new Rule(rule, replacement); this.plurals.addFirst(pluralizeRule); } public void addSingularize(String rule, String replacement) { final Rule singularizeRule = new Rule(rule, replacement); this.singulars.addFirst(singularizeRule); } public void addIrregular(String singular, String plural) { //CheckArg.isNotEmpty(singular, "singular rule"); //CheckArg.isNotEmpty(plural, "plural rule"); String singularRemainder = singular.length() > 1 ? singular.substring(1) : ""; String pluralRemainder = plural.length() > 1 ? plural.substring(1) : ""; addPluralize("(" + singular.charAt(0) + ")" + singularRemainder + "$", "$1" + pluralRemainder); addSingularize("(" + plural.charAt(0) + ")" + pluralRemainder + "$", "$1" + singularRemainder); } public void addUncountable(String... words) { if (words == null || words.length == 0) { return; } for (String word : words) { if (word != null) { uncountables.add(word.trim().toLowerCase()); } } } /** * Utility method to replace all occurrences given by the specific backreference with its uppercased form, and remove all * other backreferences. * * The Java {@link Pattern regular expression processing} does not use the preprocessing directives \l
, *\u
,\L
, and\U
. If so, such directives could be used in the replacement string * to uppercase or lowercase the backreferences. For example,\L1
would lowercase the first backreference, and *\u3
would uppercase the 3rd backreference. * * * @param input * @param regex * @param groupNumberToUppercase * @return the input string with the appropriate characters converted to upper-case */ protected static String replaceAllWithUppercase(String input, String regex, int groupNumberToUppercase) { Pattern underscoreAndDotPattern = Pattern.compile(regex); Matcher matcher = underscoreAndDotPattern.matcher(input); StringBuffer sb = new StringBuffer(); while (matcher.find()) { matcher.appendReplacement(sb, matcher.group(groupNumberToUppercase). toUpperCase()); } matcher.appendTail(sb); return sb.toString(); } /** * Completely remove all rules within this inflector. */ public void clear() { this.uncountables.clear(); this.plurals.clear(); this.singulars.clear(); } protected void initialize() { Inflector inflect = this; inflect.addPluralize("$", "s"); inflect.addPluralize("s$", "s"); inflect.addPluralize("(ax|test)is$", "$1es"); inflect.addPluralize("(octop|vir)us$", "$1i"); inflect.addPluralize("(octop|vir)i$", "$1i"); // already plural inflect.addPluralize("(alias|status)$", "$1es"); inflect.addPluralize("(bu)s$", "$1ses"); inflect.addPluralize("(buffal|tomat)o$", "$1oes"); inflect.addPluralize("([ti])um$", "$1a"); inflect.addPluralize("([ti])a$", "$1a"); // already plural inflect.addPluralize("sis$", "ses"); inflect.addPluralize("(?:([^f])fe|([lr])f)$", "$1$2ves"); inflect.addPluralize("(hive)$", "$1s"); inflect.addPluralize("([^aeiouy]|qu)y$", "$1ies"); inflect.addPluralize("(x|ch|ss|sh)$", "$1es"); inflect.addPluralize("(matr|vert|ind)ix|ex$", "$1ices"); inflect.addPluralize("([m|l])ouse$", "$1ice"); inflect.addPluralize("([m|l])ice$", "$1ice"); inflect.addPluralize("^(ox)$", "$1en"); inflect.addPluralize("(quiz)$", "$1zes"); // Need to check for the following words that are already pluralized: inflect.addPluralize("(people|men|children|sexes|moves|stadiums)$", "$1"); // irregulars inflect.addPluralize("(oxen|octopi|viri|aliases|quizzes)$", "$1"); // special rules inflect.addSingularize("s$", ""); inflect.addSingularize("(s|si|u)s$", "$1s"); // '-us' and '-ss' are already singular inflect.addSingularize("(n)ews$", "$1ews"); inflect.addSingularize("([ti])a$", "$1um"); inflect.addSingularize( "((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$", "$1$2sis"); inflect.addSingularize("(^analy)ses$", "$1sis"); inflect.addSingularize("(^analy)sis$", "$1sis"); // already singular, but ends in 's' inflect.addSingularize("([^f])ves$", "$1fe"); inflect.addSingularize("(hive)s$", "$1"); inflect.addSingularize("(tive)s$", "$1"); inflect.addSingularize("([lr])ves$", "$1f"); inflect.addSingularize("([^aeiouy]|qu)ies$", "$1y"); inflect.addSingularize("(s)eries$", "$1eries"); inflect.addSingularize("(m)ovies$", "$1ovie"); inflect.addSingularize("(x|ch|ss|sh)es$", "$1"); inflect.addSingularize("([m|l])ice$", "$1ouse"); inflect.addSingularize("(bus)es$", "$1"); inflect.addSingularize("(o)es$", "$1"); inflect.addSingularize("(shoe)s$", "$1"); inflect.addSingularize("(cris|ax|test)is$", "$1is"); // already singular, but ends in 's' inflect.addSingularize("(cris|ax|test)es$", "$1is"); inflect.addSingularize("(octop|vir)i$", "$1us"); inflect.addSingularize("(octop|vir)us$", "$1us"); // already singular, but ends in 's' inflect.addSingularize("(alias|status)es$", "$1"); inflect.addSingularize("(alias|status)$", "$1"); // already singular, but ends in 's' inflect.addSingularize("^(ox)en", "$1"); inflect.addSingularize("(vert|ind)ices$", "$1ex"); inflect.addSingularize("(matr)ices$", "$1ix"); inflect.addSingularize("(quiz)zes$", "$1"); inflect.addIrregular("person", "people"); inflect.addIrregular("man", "men"); inflect.addIrregular("child", "children"); inflect.addIrregular("sex", "sexes"); inflect.addIrregular("move", "moves"); inflect.addIrregular("stadium", "stadiums"); inflect.addUncountable("equipment", "information", "rice", "money", "species", "series", "fish", "sheep","pressure"); } }
当今中国有句顺口溜, 叫做:穷的时候种稻, 富的时候种草。我虽然 不富,但也种了几年的 草。我对种草其实懂得 不多,虽自学不辍,但 终未成才。不过到底种 了几年的草,心得和体 会总是有的。现在把我 的心得体会写出来,希 望对房前屋后有块小草 坪的朋友们,不管是穷 还是富,都有些帮助。 草地上的草,都属于禾 本科(Grass Family),与竹 子、水稻、小麦、甘蔗 和狗尾巴花是同一个科 的植物。从个体的数量 和分布的范围来讲,禾 本科植物应该是植物界 最大的科了。草本的禾 本科植物通常有两种生 长的形态,一种叫蓬草 (bunch grass),一种叫 坪草(sod grass)。用来做 草坪的草,当然都是坪 草 。坪草的物种和品种很 多,不同地区不同气候 条件种的草不一样,但 也有一些共性。一般来 说,当地商店里买的草 籽(grass seeds)和草皮( sod),都是比较适 合当地的自然条件的。 一.维护和保养草坪必 做的四件事情 1.割草。定期割草, 不仅能使草坪美观,而 且也可防止或减缓坪草 从营养生长到生殖生长 的过渡。营养生长就是 长叶子,生殖生长就是 开花结籽。很多人都知 道,春天的时候有一段 时间不割草,草就开花 结籽了。大家也见过, 边边角角割不到草的地 方,那里的草就会开花 结籽。 2.浇水。对北美大部 分地区来说,春秋天时 可视情况少浇水甚至不 浇水。草地最需要浇水 的时候是夏天,因为夏 天最热最干,水分蒸发 快。至于浇水要多频繁 ,那就看你想草地是保 绿,还是保命。如果想 保绿,那草地每星期得 有一英寸的水量。除非 有自动浇水系统,浇水 是很费时间的,也费钱 。我只想我的草地保命 ,所以我的草地夏天基 本不浇水,只在特别容 易干死的草地或在特别 干旱的年份浇点水。所 以到8-9月份的时候 ,我的草地就黄黄的了 ,有些难看。不过,一 场秋雨来,草地依旧绿 。 3.施肥。草地的肥料 应以氮素为主,钾素得 有一点,但磷的含量可 以很低。我用的最多的 草坪肥料是30-0- 4。现在有一种运动, 推崇不含磷素的草地肥 料,因为磷素施用过多 ,会引起水体(如湖泊 ,池塘)的富营养化。 施肥的话,还是得买个 撒肥机(spread er/broadca ster),手持的或 手推的型号都行,当地 商店都有卖的。没有撒 肥机,肥料会撒得很不 均匀。 4.杂草...
Comments
Post a Comment