Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   *
   * Copyright (c) 2010-2011 Oracle and/or its affiliates. All rights reserved.
   *
   * The contents of this file are subject to the terms of either the GNU
   * General Public License Version 2 only ("GPL") or the Common Development
   * and Distribution License("CDDL") (collectively, the "License").  You
   * may not use this file except in compliance with the License.  You can
  * obtain a copy of the License at
  * http://glassfish.java.net/public/CDDL+GPL_1_1.html
  * or packager/legal/LICENSE.txt.  See the License for the specific
  * language governing permissions and limitations under the License.
  *
  * When distributing the software, include this License Header Notice in each
  * file and include the License file at packager/legal/LICENSE.txt.
  *
  * GPL Classpath Exception:
  * Oracle designates this particular file as subject to the "Classpath"
  * exception as provided by Oracle in the GPL Version 2 section of the License
  * file that accompanied this code.
  *
  * Modifications:
  * If applicable, add the following below the License Header, with the fields
  * enclosed by brackets [] replaced by your own identifying information:
  * "Portions Copyright [year] [name of copyright owner]"
  *
  * Contributor(s):
  * If you wish your version of this file to be governed by only the CDDL or
  * only the GPL Version 2, indicate your decision by adding "[Contributor]
  * elects to include this software in this distribution under the [CDDL or GPL
  * Version 2] license."  If you don't indicate a single choice of license, a
  * recipient has the option to distribute your version of this file under
  * either the CDDL, the GPL Version 2 or to extend the choice of license to
  * its licensees as provided above.  However, if you add GPL Version 2 code
  * and therefore, elected the GPL Version 2 license, then the option applies
  * only if the new code is made subject to such option by the copyright
  * holder.
  */
 package com.sun.jersey.core.impl.provider.entity;
 
 import java.util.List;

API for performing inflections (pluralization, singularization, and so on) on various strings. These inflections will be useful in code generators that convert things like database table names into Java class names.

The getInstance() method returns a singleton instance of this class with a default set of rules, which can then be customized. Rules added during customization will take precedence over the standard ones. Use the addIrregular(), addPlural(), addSingular(), and addUncountable() methods to add additional rules ot the default ones.

IMPLEMENTATION NOTE - The default implementation is intended to be functionally compatible with the Inflector::inflections class in Ruby on Rails. The gsub() method on Ruby strings matches regular expressions anywhere in the input. However, nearly all of the actual patterns used in this module use $ at the end to match the end of the input string (so that only the last word in a multiple word phrase will be singularized or pluralized). Therefore, the Java versions of the regular expressions have been modified to capture all text before the interesting characters at the end, and emit them as part of the result, so that the entire string can be matched against a pattern once.

Author(s):
Florian Rosenberg
 
 public class Inflector {
 
 
     // ------------------------------------------------------------ Constructors
     

Private constructor to avoid instantiation.

 
     private Inflector() {
 
         addPlural("$""s"false);
         addPlural("(.*)$""\\1s");
         addPlural("(.*)(ax|test)is$""\\1\\2es");
         addPlural("(.*)(octop|vir)us$""\\1\\2i");
         addPlural("(.*)(alias|status)$""\\1\\2es");
         addPlural("(.*)(bu)s$""\\1\\2ses");
         addPlural("(.*)(buffal|tomat)o$""\\1\\2oes");
         addPlural("(.*)([ti])um$""\\1\\2a");
         addPlural("(.*)sis$""\\1ses");
         addPlural("(.*)(?:([^f])fe|([lr])f)$""\\1\\3ves");
         addPlural("(.*)(hive)$""\\1\\2s");
         addPlural("(.*)(tive)$""\\1\\2s"); // Added for consistency with singular rules
         addPlural("(.*)([^aeiouy]|qu)y$""\\1\\2ies");
         addPlural("(.*)(series)$""\\1\\2"); // Added for consistency with singular rules
         addPlural("(.*)(movie)$""\\1\\2s"); // Added for consistency with singular rules
         addPlural("(.*)(x|ch|ss|sh)$""\\1\\2es");
         addPlural("(.*)(matr|vert|ind)ix|ex$""\\1\\2ices");
         addPlural("(.*)(o)$""\\1\\2es"); // Added for consistency with singular rules
        addPlural("(.*)(shoe)$""\\1\\2s"); // Added for consistency with singular rules
        addPlural("(.*)([m|l])ouse$""\\1\\2ice");
        addPlural("^(ox)$""\\1en");
        addPlural("(.*)(vert|ind)ex$""\\1\\2ices"); // Added for consistency with singular rules
        addPlural("(.*)(matr)ix$""\\1\\2ices"); // Added for consistency with singular rules
        addPlural("(.*)(quiz)$""\\1\\2zes");
        addSingular("(.*)s$""\\1");
        addSingular("(.*)(n)ews$""\\1\\2ews");
        addSingular("(.*)([ti])a$""\\1\\2um");
        addSingular("(.*)((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$""\\1\\2sis");
        addSingular("(.*)(^analy)ses$""\\1\\2sis");
        addSingular("(.*)([^f])ves$""\\1\\2fe");
        addSingular("(.*)(hive)s$""\\1\\2");
        addSingular("(.*)(tive)s$""\\1\\2");
        addSingular("(.*)([lr])ves$""\\1\\2f");
        addSingular("(.*)([^aeiouy]|qu)ies$""\\1\\2y");
        addSingular("(.*)(s)eries$""\\1\\2eries");
        addSingular("(.*)(m)ovies$""\\1\\2ovie");
        addSingular("(.*)(x|ch|ss|sh)es$""\\1\\2");
        addSingular("(.*)([m|l])ice$""\\1\\2ouse");
        addSingular("(.*)(bus)es$""\\1\\2");
        addSingular("(.*)(o)es$""\\1\\2");
        addSingular("(.*)(shoe)s$""\\1\\2");
        addSingular("(.*)(cris|ax|test)es$""\\1\\2is");
        addSingular("(.*)(octop|vir)i$""\\1\\2us");
        addSingular("(.*)(alias|status)es$""\\1\\2");
        addSingular("^(ox)en""\\1");
        addSingular("(.*)(vert|ind)ices$""\\1\\2ex");
        addSingular("(.*)(matr)ices$""\\1\\2ix");
        addSingular("(.*)(quiz)zes$""\\1\\2");
        addIrregular("child""children");
        addIrregular("man""men");
        addIrregular("move""moves");
        addIrregular("person""people");
        addIrregular("sex""sexes");
        addUncountable("equipment");
        addUncountable("fish");
        addUncountable("information");
        addUncountable("money");
        addUncountable("rice");
        addUncountable("series");
        addUncountable("sheep");
        addUncountable("species");
    }
    // -------------------------------------------------------- Static Variables
    

The singleton instance returned by the default getInstance() method.

    private transient static Inflector instance = null;
    

List of Replacers for performing replacement operations on matches for plural words.

    private List<Replacerplurals = new LinkedList<Replacer>();
    

List of Replacers for performing replacement operations on matches for addSingular words.

    private List<Replacersingulars = new ArrayList<Replacer>();
    

List of words that represent addUncountable concepts that cannot be pluralized or singularized.

    private List uncountables = new LinkedList();
    // ------------------------------------------------------ Instance Variables
    // ---------------------------------------------------------- Static Methods
    

Return a fully configured Inflector instance that can be used for performing transformations.

    public static Inflector getInstance() {
        if ( == null) {
             = new Inflector();
        }
        return ;
    }
    // ---------------------------------------------------------- Public Methods
    

Convert strings to EmbeddedCamelCase. Embedded underscores will be removed.

Parameters:
word Word to be converted
    public String camelize(String word) {
        return camelize(wordfalse);
    }

    

Convert word strings consisting of lower case letters and underscore characters between words into embeddedCamelCase or EmbeddedCamelCase, depending on the lower flag. Embedded underscores will be removed. Embedded '/' characters will be replaced by '.', making this method useful in converting path-like names into fully qualified classnames.

IMPLEMENTATION DIFFERENCE - The Rails version of this method also converts '/' characters to '::' because that reflects the normal syntax for fully qualified names in Ruby.

InputOutput
"foo_bar", false"FooBar"
"foo_bar", true"fooBar"
"foo_bar/baz", false"FooBar.Baz"
"foo_bar/baz", true"fooBar.Baz"

Parameters:
word Word to be converted
flag Flag indicating that the initial character should be lower cased instead of upper cased
    public String camelize(String wordboolean flag) {
        if (word.length() == 0) {
            return word;
        }
        StringBuffer sb = new StringBuffer(word.length());
        if (flag) {
            sb.append(Character.toLowerCase(word.charAt(0)));
        } else {
            sb.append(Character.toUpperCase(word.charAt(0)));
        }
        boolean capitalize = false;
        for (int i = 1; i < word.length(); i++) {
            char ch = word.charAt(i);
            if (capitalize) {
                sb.append(Character.toUpperCase(ch));
                capitalize = false;
            } else if (ch == '_') {
                capitalize = true;
            } else if (ch == '/') {
                capitalize = true;
                sb.append('.');
            } else {
                sb.append(ch);
            }
        }
        return sb.toString();
    }

    

Create and return a simple class name that corresponds to a addPlural table name. Any leading schema name will be trimmed.

InputOutput
"foo_bars""FooBar"
"baz""Baz"

Parameters:
tableName Table name to be converted
    public String classify(String tableName) {
        int period = tableName.lastIndexOf('.');
        if (period >= 0) {
            tableName = tableName.substring(period + 1);
        }
        return camelize(singularize(tableName));
    }

    

Replace underscores in the specified word with dashes.

InputOutput
"foo_bar""foo-bar"
"baz""baz"

Parameters:
word Word to be converted
    public String dasherize(String word) {
        return word.replace('_''-');
    }

    

Remove any package name from a fully qualified class name, returning only the simple classname.

InputOutput
"java.util.Map""Map"
"String""String"

Parameters:
className Fully qualified class name to be converted
    public String demodulize(String className) {
        int period = className.lastIndexOf('.');
        if (period >= 0) {
            return className.substring(period + 1);
        } else {
            return className;
        }
    }

    

Create and return a foreign key name from a class name, separating the "id" suffix with an underscore.

    public String foreignKey(String className) {
        return foreignKey(classNametrue);
    }

    

Create and return a foreign key name from a class name, optionally inserting an underscore before the "id" portion.

InputOutput
"com.mymodel.Order", false"orderid"
"com.mymodel.Order", true"order_id"
"Message", false"messageid"
"Message", true"message_id"

Parameters:
className Class name for which to create a foreign key
underscore Flag indicating whether an underscore should be emitted between the class name and the "id" suffix
    public String foreignKey(String classNameboolean underscore) {
        return underscore(demodulize(className) + (underscore ? "_id" : "id"));
    }

    

Capitalize the first word in a lower cased and underscored string, turn underscores into spaces, and string any trailing "_id". Like titleize(), this is meant for creating pretty output, and is not intended for code generation.

InputOutput
"employee_salary""Employee salary"
"author_id""Author"

Parameters:
words Word string to be converted
    public String humanize(String words) {
        if (words.endsWith("_id")) {
            words = words.substring(0, words.length() - 3);
        }
        StringBuffer sb = new StringBuffer(words.length());
        sb.append(Character.toUpperCase(words.charAt(0)));
        for (int i = 1; i < words.length(); i++) {
            char ch = words.charAt(i);
            if (ch == '_') {
                sb.append(' ');
            } else {
                sb.append(ch);
            }
        }
        return sb.toString();
    }

    

Turn a number into a corresponding ordinal string used to denote the position in an ordered sequence.

InputOutput
1"1st"
2"2nd"
3"3rd"
4"rth"
1002"1002nd"
2012"2012th"

Parameters:
number Number to be converted
    public String ordinalize(int number) {
        int modulo = number % 100;
        if ((modulo >= 11) && (modulo <= 13)) {
            return "" + number + "th";
        }
        switch (number % 10) {
            case 1:
                return "" + number + "st";
            case 2:
                return "" + number + "nd";
            case 3:
                return "" + number + "rd";
            default:
                return "" + number + "th";
        }
    }

    

Return a addPlural version of the specified (addSingular) word.

Parameters:
word Singular word to be converted
    public String pluralize(String word) {
        // Scan uncountables and leave alone
        for (int i = 0; i < .size(); i++) {
            if (.get(i).equals(word)) {
                return word;
            }
        }
        // Scan our patterns for a match and return the correct replacement
        for (int i = 0; i < .size(); i++) {
            String replacement = .get(i).replacement(word);
            if (replacement != null) {
                return replacement;
            }
        }
        // Return the original string unchanged
        return word;
    }

    

Return a addSingular version of the specified (addPlural) word.

Parameters:
word Plural word to be converted
    public String singularize(String word) {
        // Scan uncountables and leave alone
        for (int i = 0; i < .size(); i++) {
            if (.get(i).equals(word)) {
                return word;
            }
        }
        // Scan our patterns for a match and return the correct replacement
        for (int i = 0; i < .size(); i++) {
            String replacement = .get(i).replacement(word);
            if (replacement != null) {
                return replacement;
            }
        }
        // Return the original string unchanged
        return word;
    }

    

Convert the simple name of a model class into the corresponding name of a database table, by uncamelizing, inserting underscores, and pluralizing the last word.

InputOutput
"RawScaledScorer""raw_scaled_scorers"
"fancyCategory""fancy_categories"

Parameters:
className Class name to be converted
    public String tableize(String className) {
        return pluralize(underscore(className));
    }

    

Capitalize all the words, and replace some characters in the string to create a nicer looking title. This is meant for creating pretty output, and is not intended for code generation.

InputOutput
"the honeymooners""The Honeymooners"
"x-men: the last stand""X Men: The Last Stand"

Parameters:
words Word string to be converted
    public String titleize(String words) {
        StringBuffer sb = new StringBuffer(words.length());
        boolean capitalize = true// To get the first character right
        for (int i = 0; i < words.length(); i++) {
            char ch = words.charAt(i);
            if (Character.isWhitespace(ch)) {
                sb.append(' ');
                capitalize = true;
            } else if (ch == '-') {
                sb.append(' ');
                capitalize = true;
            } else if (capitalize) {
                sb.append(Character.toUpperCase(ch));
                capitalize = false;
            } else {
                sb.append(ch);
            }
        }
        return sb.toString();
    }
    public String decapitalize(String word) {
        // do nothing if null or empty
        if ((word == null) || (word.length() < 1)) {
            return word;
        }
        // or if already decapitalized
        char first =  word.charAt(0);
        if (Character.isLowerCase(first)) {
            return word;
        }
        // otherwise turn the first character to lower case and attach the rest
        StringBuilder sb = new StringBuilder(word.length());
        sb.append(Character.toLowerCase(first));
        sb.append(word.substring(1));
        return sb.toString();
    }

    

The reverse of camelize(), makes an underscored form from the expression in the string. Changes "." to "/" to convert fully qualified class names into paths.

InputOutput
"FooBar""foo_bar"
"fooBar""foo_bar"
"FooBar.Baz""foo_bar/baz"
"FooBar.Baz""foo_bar/baz"

Parameters:
word Camel cased word to be converted
    public String underscore(String word) {
        StringBuffer sb = new StringBuffer(word.length() + 5);
        boolean uncapitalize = false;
        for (int i = 0; i < word.length(); i++) {
            char ch = word.charAt(i);
            if (uncapitalize) {
                sb.append(Character.toLowerCase(ch));
                uncapitalize = false;
            } else if (ch == '.') {
                sb.append('/');
                uncapitalize = true;
            } else if (Character.isUpperCase(ch)) {
                if (i > 0) {
                    sb.append('_');
                }
                sb.append(Character.toLowerCase(ch));
            } else {
                sb.append(ch);
            }
        }
        return sb.toString();
    }
    // --------------------------------------------------- Customization Methods
    

Add the addSingular and addPlural forms of words that cannot be converted using the normal rules.

Parameters:
singular Singular form of the word
plural Plural form of the word
    public void addIrregular(String singularString plural) {
        addPlural("(.*)(" + singular.substring(0, 1) + ")" + singular.substring(1) + "$",
                "\\1\\2" + plural.substring(1));
        addSingular("(.*)(" + plural.substring(0, 1) + ")" + plural.substring(1) + "$",
                "\\1\\2" + singular.substring(1));
    }

    

Add a match pattern and replacement rule for converting addPlural forms to addSingular forms. By default, matches will be case insensitive.

Parameters:
match Match pattern regular expression
rule Replacement rule
    public void addPlural(String matchString rule) {
        addPlural(matchruletrue);
    }

    

Add a match pattern and replacement rule for converting addPlural forms to addSingular forms.

Parameters:
match Match pattern regular expression
rule Replacement rule
insensitive Flag indicating this match should be case insensitive
    public void addPlural(String matchString ruleboolean insensitive) {
        .add(0, new Replacer(matchruleinsensitive));
    }

    

Add a match pattern and replacement rule for converting addSingular forms to addPlural forms. By default, matches will be case insensitive.

Parameters:
match Match pattern regular expression
rule Replacement rule
    public void addSingular(String matchString rule) {
        addSingular(matchruletrue);
    }

    

Add a match pattern and replacement rule for converting addSingular forms to addPlural forms.

Parameters:
match Match pattern regular expression
rule Replacement rule
insensitive Flag indicating this match should be case insensitive
    public void addSingular(String matchString ruleboolean insensitive) {
        .add(0, new Replacer(matchruleinsensitive));
    }

    

Add a word that cannot be converted between addSingular and addPlural.

Parameters:
word Word to be added
    public void addUncountable(String word) {
        .add(0, word.toLowerCase());
    }
    // --------------------------------------------------------- Private Classes
    

Internal class that uses a regular expression matcher to both match the specified regular expression to a specified word, and (if successful) perform the appropriate substitutions.

    private class Replacer {
        // --------------------------------------------------------- Constructor
        public Replacer(String matchString ruleboolean insensitive) {
             = Pattern.compile(match,
                    insensitive ? . : 0);
            this. = rule;
        }
        // -------------------------------------------------- Instance Variables
        private Pattern pattern = null;
        private String rule = null;
        // ------------------------------------------------------ Public Methods

        
Replace the input if it matches the pattern.

Parameters:
input the input string.
Returns:
the replacement, if the input matches, otherwise null.
        public String replacement(String input) {
            Matcher matcher = .matcher(input);
            if (matcher.matches()) {
                StringBuffer sb = new StringBuffer();
                boolean group = false;
                for (int i = 0; i < .length(); i++) {
                    char ch = .charAt(i);
                    if (group) {
                        sb.append(matcher.group(Character.digit(ch, 10)));
                        group = false;
                    } else if (ch == '\\') {
                        group = true;
                    } else {
                        sb.append(ch);
                    }
                }
                return sb.toString();
            } else {
                return null;
            }
        }
    }
New to GrepCode? Check out our FAQ X