Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

The Challenge

I was reading Google's Java Style Guide the other day and stumbled over their algorithm to convert any arbitrary string into camelCase notation. In this challenge you have to implement this algorithm since you dont want to do all this stuff in your head when you are writing your super competitive Java submissions to code-golf challenges.

Note: I made some small adjustments to the algorithm. You need to use the one specified below.

The algorithm

You start with an arbitrary input string and apply the following operations to it:

  1. Remove all apostrophes `'
  2. Split the result into words by splitting at
    • characters that are not alphanumerical and not a digit [^a-zA-Z0-9]
    • Uppercase letters which are surrounded by lowercase letters on both sides. abcDefGhI jk for example yields abc Def Ghi jk
  3. Lowercase every word.
  4. Uppercase the first character of every but the first word.
  5. Join all words back together.

Additional notes

  • The input will only contain printable ASCII.
  • If a digit is the first letter in a word, leave it as it is and don't capalize something else in this word.
  • The input will always have at least one character.

Rules

Test cases

"Programming Puzzles & Code Golf" -> "programmingPuzzlesCodeGolf"
"XML HTTP request" -> "xmlHttpRequest"
"supports IPv6 on iOS?" -> "supportsIpv6OnIos"
"SomeThing w1th, apo'strophe's and' punc]tuation" -> "someThingW1thApostrophesAndPuncTuation"
"nothing special" -> "nothingSpecial"
"5pecial ca5e" -> "5pecialCa5e"
"1337" -> "1337"
"1337-spEAk" -> "1337Speak"
"abcD" -> "abcd"
"a" -> "a"
"B" -> "b"

Happy Coding!

share|improve this question
3  
Interesting, I never knew this was called "camelCase". Name is fitting I suppose... – Ashwin Gupta Mar 3 at 4:53
4  
There are more: snake_case & PascalCase – Martijn Mar 3 at 8:50
12  
@Martijn snake_case because of Python, of course. FORTH also has FORTHCASE and APL has unreadable in any case – cat Mar 3 at 14:40

12 Answers 12

up vote 12 down vote accepted

Retina, 56 bytes

Byte count assumes ISO 8859-1 encoding.

T`'\`
S_`\W|_|(?<=[a-z])(?=[A-Z][a-z])
T`L`l
T`l`L`¶.
¶

Try it online!

Explanation

This implements the specification quite literally:

T`'\`

Remove apostrophes and backticks.

S_`\W|_|(?<=[a-z])(?=[A-Z][a-z])

Split the string around non-word characters (in regex this also excludes digits and underscores), or underscores or positions that have a lower case letter on the left and and upper case, lower case on the right. This would create some empty segments when there are two non-letter, non-digit characters in a row, or more important at the beginning of the string. We get rid of those with the _ option. Here, "splitting" means put each remaining part on its own line.

T`L`l

Convert everything to lower case.

T`l`L`¶.

Convert each character that occurs after the linefeed to upper case. This will conveniently skip the first word because there's no linefeed in front of it.

Get rid of the linefeeds to join everything back together.

share|improve this answer
    
You beat me to it. Nice one! – mbomb007 Mar 2 at 20:01
    
This question may be a bit weird, but...should I post my answer if it's shorter than yours and also in Retina? I was working on it before your answer appeared, but then it did and now I don't know if I should post it. – daavko Mar 2 at 20:11
5  
@daavko Sure, post it (I usually decide based on how different the approach is to the existing answer... if it's the exact same thing with a byte shaved off somewhere I normally just comment on that answer, but if it's a lot shorter of a different approach, then I'd just post a separate answer). – Martin Ender Mar 2 at 20:12
    
@MartinBüttner Now that I look at it, it's the same approach, but as a simple expression, rather than a difficult-to-understand (for me, at least) lookaround (or whatever it is). I'll just put it here as a comment: Try it online – daavko Mar 2 at 20:18
2  
@daavko The lookaround is necessary though. Note that your answer doesn't retain the capitalisation of Thing although it should. – Martin Ender Mar 2 at 20:19

Java, 198 190 bytes

+3 bytes because I forgot that \W+ == [^a-zA-Z0-9_]+ and I need to match [^a-zA-Z0-9]+

-11 bytes thanks to user20093 - ?: instead of if/else

Because, Java.

s->{String[]a=s.replaceAll("`|'","").split("[\\W_]+|(?<=[a-z])(?=[A-Z][a-z])");s="";for(String w:a){String t=w.toLowerCase();s+=a[0]==w?t:t.toUpperCase().charAt(0)+t.substring(1);}return s;}

This is a lambda. Call like so:

UnaryOperator<String> op = s->{String[]a=s.replaceAll("`|'","").split("[\\W_]+|(?<=[a-z])(?=[A-Z][a-z])");s="";for(String w:a){String t=w.toLowerCase();s+=a[0]==w?t:t.toUpperCase().charAt(0)+t.substring(1);}return s;};
System.out.println(op.apply("Programming Puzzles & Code Golf"));

Readable version:

public static String toCamelCase(String s) {
    String[] tokens = s
            .replaceAll("`|'", "") // 1. Remove all apostrophes
            .split("[\\W_]+|(?<=[a-z])(?=[A-Z][a-z])"); // 2. Split on [\W_]+ or between [a-z] and [A-Z][a-z]
    s = ""; // Reusing s for building output is cheap
    for (String token : tokens) {
        String lowercaseToken = token.toLowerCase(); // 3. Lowercase every word
        s += tokens[0].equals(token)?lowercaseToken:lowercaseToken.toUpperCase().charAt(0) + lowercaseToken.substring(1); // 4. Uppercase first char of all but first word
        // ^ 5. Join all words back together
    }
    return s;
}
share|improve this answer
1  
It's not Swift... – CalculatorFeline Mar 3 at 4:17
2  
Welcome to Programming Puzzles & Code Golf! This is a nice first answer! – Alex A. Mar 3 at 4:28
1  
@CatsAreFluffy What? – cat Mar 3 at 14:49
    
if you replace conditional statement(if/else) with conditional expression (?:) you could save around 9 bytes – user902383 Mar 4 at 11:55
    
Don't know how I missed that @user902383 - added for -11 bytes. Unfortunately I had to add 3 as well to match _ as a token delimiter. – CAD97 Mar 4 at 19:12

JavaScript (ES6), 156 154 152 148 145 141 bytes

Thanks @Neil (6 bytes), @ETHproductions (2 bytes), and @edc65 (7 bytes)

a=>a[r='replace'](/`|'/g,a='')[r](/[a-z](?=[A-Z][a-z])/g,'$& ')[r](/[^\W_]+/gi,b=>a+=(a?b[0].toUpperCase():'')+b.slice(!!a).toLowerCase())&&a

Removes apostrophes, then does a replace to split on special characters/before surrounded capitals, then combines with proper casing. Unfortunately, toLowerCase() and toUpperCase() are annoyingly long and hard to avoid here...

share|improve this answer
1  
I was working on a different approach which your b.slice(i>0) approach blows out of the water, but in the mean time my match regex of /[A-Z]?([a-z0-9]|[0-9A-Z]{2,})+([A-Z](?![a-z]))?/g does appear to save 2 bytes over your otherwise ingenious replace approach. – Neil Mar 2 at 20:28
1  
Or I could just save 2 bytes on your replace directly: replace(/[a-z](?=[A-Z][a-z])/g,'$& ') – Neil Mar 2 at 20:30
1  
Usually match...map can be replaced with replace – edc65 Mar 2 at 21:45
1  
@edc65 I get a minimum of 160 bytes with that approach: a=>a.replace(/`|'/g,'').replace(/[a-z](?=[A-Z][a-z])/g,'$& ').replace(/[\W_]*([a-z0-9]+)[\W_]*/gi,(_,b,i)=>(i?b[0].toUpperCase():'')+b.slic‌​e(i>0).toLowerCase()) – ETHproductions Mar 2 at 21:50
2  
On the other hand, I would like to offer b=>a+=(a?b[0].toUpperCase():'')+b.slice(!!a).toLowerCase() which I believe saves you another 4 bytes. – Neil Mar 3 at 0:28

vim, 69 68 66

:s/[`']//g<cr>:s/[a-z]\zs\ze[A-Z][a-z]\|\W\|_/\r/g<cr>o<esc>guggj<C-v>GgU:%s/\n<cr>

vim shorter than Perl?! What is this madness?

:s/[`']//g<cr>           remove ` and '
:s/                      match...
 [a-z]\zs\ze[A-Z][a-z]   right before a lowercase-surrounded uppercase letter
 \|\W\|_                 or a non-word char or underscore
 /\r/g<cr>               insert newlines between parts
o<esc>                   add an extra line at the end, necessary later...
gugg                     lowercasify everything
j                        go to line 2 (this is why we added the extra line)
<C-v>G                   visual select the first char of all-but-first line
gU                       uppercase
:%s/\n<cr>               join all lines into one

Thanks to Neil for spotting a useless keystroke!

share|improve this answer
    
I can see why the last :s has a % but why the inconsistency in the first two? – Neil Mar 3 at 0:30
    
@Neil Bah, muscle memory. Thanks! – Doorknob Mar 3 at 0:53
4  
Manages to be less readable than Perl, too +1 – cat Mar 3 at 14:41
    
I'm totally adding this to my .vimrc – moopet Mar 4 at 10:58
1  
@fruglemonkey 1. :%j<cr> is equivalent and shorter. 2. That adds spaces between lines. – Doorknob Mar 5 at 5:36

Mathematica 10.1, 101 bytes

""<>(ToCamelCase@{##2}~Prepend~ToLowerCase@#&@@StringCases[StringDelete[#,"`"|"'"],WordCharacter..])&

Uses the undocumented ToCamelCase, which works similarly to Capitalize but sets other characters to lowercase.

share|improve this answer
    
Not in 10.3.0.. – A Simmons Mar 3 at 14:04
    
Is ToCamelCase[n_,m_]:=n<>Capitalize/@m correct? Seems like it. And why use Prepend when #~ToCamelCase~{##2} works? – CalculatorFeline Mar 3 at 17:29
    
@CatsAreFluffy That gives me ToCamelCase::argx: ToCamelCase called with 2 arguments; 1 argument is expected. – LegionMammal978 Mar 3 at 22:23
    
Well, how does CamelCase work? Just ToCamelCase[n_]:=""<>Capitalize/@n? – CalculatorFeline Mar 4 at 16:22
    
@CatsAreFluffy, see this. – LegionMammal978 Mar 5 at 1:02

Julia, 98 89 bytes

s->lcfirst(join(map(ucfirst,split(replace(s,r"['`]",""),r"[a-z]\K(?=[A-Z][a-z])|\W|_"))))

This is an anonymous function that accepts a string and returns a string. To call it, assign it to a variable.

The approach here is the same as in Doorknob's Perl answer: replace apostrophes and backticks with the empty string, split into an array on a regular expression that matches the necessary cases, map the ucfirst function over the array to uppercase the first letter of each element, join the array back into a string, and lcfirst the result to convert the first character to lowercase.

share|improve this answer
    
I've always liked Julia as a more functional, more interesting Python but I hate the end syntax. Maybe I'll just use anonymous functions for everything, then I never have to type end :D – cat Mar 3 at 14:51

Perl 67 + 1 = 68 bytes

y/'`//d;s/([a-z](?=[A-Z][a-z]))|\W|_/$1 /g;$_=lc;s/^ +| +(.)/\u$1/g

Requires the -p flag, and -l for multi line:

$ perl -pl camelCase.pl input.txt
programmingPuzzlesCodeGolf
xmlHttpRequest
supportsIpv6OnIos:
someThingW1thApostrophesAndPuncTuation
nothingSpecial
5pecialCa5e
1337
1337Speak
abcd

How it works:

y/'`//d;                            # Remove ' and `
s/([a-z](?=[A-Z][a-z]))|\W|_/$1 /g; # Replace according to '2. Split...' this will create
                                    #   a space separated string.
$_=lc;                              # lower case string
s/^ +| +(.)/\u$1/g                  # CamelCase the space separated string and remove any
                                    #   potential leading spaces.
share|improve this answer

Perl, 87 80 78 bytes

y/'`//d;$_=join'',map{ucfirst lc}split/[a-z]\K(?=[A-Z][a-z])|\W|_/,$_;lcfirst

Byte added for the -p flag.

First, we use the y/// transliteration operator to delete all '` characters in the input:

y/'`//d;

Then comes the meat of the code:

                         split/[a-z]\K(?=[A-Z][a-z])|\W|_/,$_;

(split the input string $_ in the appropriate locations, using the fancy \K in the match string to exclude the portion preceding it from the actual match)

          map{ucfirst lc}

(map over each split portion of the string and make the entire string lowercase, then make the first character of the modified string uppercase)

$_=join'',

(join on empty string and re-assign to magic underscore $_, which gets printed at the end)

Finally, we lowercase the first letter by regex-matching it and using \l in the replacement string with a builtin, saving 2 bytes over the previous method:

lcfirst

Thanks to @MartinBüttner for 7 bytes ([^a-zA-Z\d] -> \W|_)!

share|improve this answer
1  
How I envy that \K... ;) – Martin Ender Mar 2 at 20:25

Lua, 127 Bytes

t=''l=t.lower z=io.read()for x in z:gmatch('%w+')do t=t..(t==''and l(x:sub(1,1))or x:sub(1,1):upper())..l(x:sub(2))end return t

Accepts a string from stdin and returns camelized results.

Probably still gonna look for a better solution as storing everything in a variable feels inefficient.

But anyhow, pretty simple in general:

 z:gmatch('%w+')

This is the beauty that saved me a bit of bytes. gmatch will split the string based on the pattern: %w+ which grabs only alphanumerics.

After that it's simple string operations. string.upper, string.lower and done.

share|improve this answer

Kotlin, 160 Bytes

fun a(s: String)=s.replace(Regex("['`]"),"").split(Regex("[\\W_]+|(?<=[a-z])(?=[A-Z][a-z])")).map{it.toLowerCase().capitalize()}.joinToString("").decapitalize()

My goal was to be Scala, the other "alternative Java", so I'm somewhat happy with my results. I stole the regex from the Java answer.

Test it with:

fun main(args: Array<String>) {
    val testCases = arrayOf(
            "Programming Puzzles & Code Golf",
            "XML HTTP request",
            "supports IPv6 on iOS?",
            "SomeThing w1th, apo'strophe's and' punc]tuation",
            "nothing special",
            "5pecial ca5e",
            "1337",
            "1337-spEAk",
            "abcD",
            "a",
            "B")
    testCases.forEach { println(a(it)) }

}
share|improve this answer
    
At this point I think everyone is "borrowing" the optimized regex \W|_|(?<=[a-z])(?=[A-Z][a-z]) or slightly modifying it eg. [\W_]+ – CAD97 Mar 4 at 20:54

Scala, 181 170 144

def f(s:String)={val l=s.replaceAll("'|`","")split("[\\W_]+|(?<=[a-z])(?=[A-Z][a-z])")map(_.toLowerCase);l(0)+l.tail.map(_.capitalize).mkString}

Tester:

val testCases = List(
  "Programming Puzzles & Code Golf" -> "programmingPuzzlesCodeGolf",
  "XML HTTP request" -> "xmlHttpRequest"
  // etc
)
println(testCases.map(t=>if(t._2!=f(t._1))s"FAIL:${f(t._1)}"else"PASS").mkString("\n"))

Props to CAD97 and apologies to Nathan Merrill :)

share|improve this answer
1  
You can save 6 bytes by replacing [^a-zA-Z0-9]+ with [\\W_]+. – CAD97 Mar 4 at 20:53

C 272 characters

C program pass string to camelCase in quotes as argument 1. There are lot's of gotchas in this problem statement...

#define S strlen(t)
#define A isalnum(t[i])
j=0;main(i,v)char**v;{char*p=v[1],*t;char o[99]={0};while(t=strtok(p," [{(~!@#$%^*-+=)}]")){i=0;p+=S+1;while((!A)&&i<S)i++;if(i!=S){o[j]=((j++==0)?tolower(t[i++]):toupper(t[i++]));while(i<S){if(A)o[j++]=t[i];i++;}}}puts(o);}
share|improve this answer
    
You need to #include<string.h> for strlen, strtok, and toupper, and #include<ctype.h> for isalnum. – Mego Mar 4 at 22:03
    
I didn't need it using gcc 3.4.4 in cygwin. They must be automatically linked in, assuming extern int. – cleblanc Mar 4 at 22:05
    
With ./camel "Programming Puzzles & Code Golf" on cygwin (compiled with gcc 3.4.4), I get programmingPuzzlesCodeEGolf. Same output with 5.3.0. – Mego Mar 4 at 22:08
    
Crap. me too. I must've created a bug while golfing it. I'm looking at it now... – cleblanc Mar 4 at 22:12
    
The problem was I added the other tokenizer strings after golfing and didn't test it well enough. If you remove the '&' from the strtok call it works on that input. – cleblanc Mar 4 at 22:26

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.