implements Elegance {

// Elwyn Malethan's musings on software development, mountain biking and general navel–gazing...

Humanise CamelCase in Java (non hungover version)

Yesterday, I posted a hangover–inspired camel–case humaniser. Today – with the benefit of a clearer mind I decided I didn't like what I'd written much. In fact I thought it was at best ugly, at worst not at all that clear. So I set about implementing a cleaner solution and factoring the changes into Seemore.

There are those who say that it doesn‘t matter what code looks like as long as it passes the tests. They‘ll say that if it passes the tests then it does what it‘s meant to do, who cares that it looks like a turd?! Neither the customer nor the JVM (in the case of Java) cares what the code looks like, so why should we? Some even say that even unit tests don't matter — there's entertaining discussion at the end of that article as well.

Any experienced developer will know that it does matter what code looks like. Or, more specifically how readable it is. Devs who‘ve been about for a while will have been on the receiving end of a plethora of badly written classes – I know I have over the years – only to spend hours tracing through the execution with a debugger and more hours trying to decipher badly named classes. methods and variables. All in a vain attempt to extract some meaning.

It matters what code looks like! I heard somewhere (can't remember where) that – when actively developing (i.e. producing code) – developers spend only 10% of their time writing code, the rest of the time is spent reading existing code. It matters what code looks like!

It also matters a great deal that there are unit tests. In this case, if there were no unit tests, evaluating the success of the following re-implementation would have been far more difficult, certainly less repeatable. Anyway, here‘s the (hopefully) more readable version.

import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class HumaniseCamelCase {
    //----------------------------------------------------------------------- Static Properties and Constants

    private static final String CAMEL_CASE_PATTERN = "([A-Z]|[a-z])[a-z]*";

    //----------------------------------------------------------------------- Instance Properties

    private String humanisedString;
    private String acronym;

    //----------------------------------------------------------------------- Instance Methods

    /**
     * Converts a camelCase to a more human form, with spaces. E.g. 'Camel case'
     *
     * @param camelCaseString
     * @return a humanised version of a camelCaseString if it is indeed camel-case. Returns the
     * original string if it is'nt camel-case
     */
    public String humanise(String camelCaseString) {
        reset();
        Matcher wordMatcher = camelCaseWordMatcher(camelCaseString);
        while(wordMatcher.find()) {
            String word = wordMatcher.group();
            boolean wordIsSingleCapitalLetter = word.matches("^[A-Z]$");
            if(wordIsSingleCapitalLetter) {
                addToAcronym(word);
            } else {
                appendAcronymIfThereIsOne();
                appendWord(word);
            }
        }
        appendAcronymIfThereIsOne();
        return humanisedString.length() > 0 ? humanisedString : camelCaseString;
    }

    private Matcher camelCaseWordMatcher(String camelCaseString) {
        return Pattern.compile(CAMEL_CASE_PATTERN).matcher(camelCaseString);
    }

    private void reset() {
        humanisedString = "";
        acronym = "";
    }

    private void addToAcronym(String word) {
        acronym += word;
    }

    private void appendWord(String word) {
        boolean firstWord = humanisedString.length() == 0;
        humanisedString += firstWord ? capitaliseFirstLetter(word) : " " + word.toLowerCase();
    }

    private void appendAcronymIfThereIsOne() {
        if(acronym.length() > 0) {
            boolean firstWord = humanisedString.length() == 0;
            humanisedString += firstWord ? acronym : " " + acronym;
            acronym = "";
        }
    }

    private String capitaliseFirstLetter(String str) {
        return str.substring(0, 1).toUpperCase() + str.substring(1);
    }

}

I‘m torn as to whether more readable means more elegant, but that can be a belly–button inspection for another day.

First published on Feb 9, 2009. Last updated on: Dec 30, 2009.

Comments (2)

Leave a reply »

 
 

AWESOME!!!

 

Exactly what I needed to go with my bit of reflection code. Really nicely written, thanks a bunch!

Leave a Reply

Your name
 
Email
 
Website
 
Comment

You may use Textile notation here
 
 

Please perform this simple arithmetic test to prove you are human