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

In that Coding Golf, you should convert one coding convention with TitleCase to lower_case_with_underscores. And... vice versa!

Specification

Change the casing in a following way:

  • If underscore character is a delimiter, change the casing to Title Case without any of delimiter.
  • If there are multiple words with no delimiter, change the casing to lower case and add an underscore character as a delimiter.
  • In case of only one word (or one character): change the casing to Title Case if the word starts with lower case; change the casing to lower case if the word starts with the upper case.

Allowed characters:

  • A to Z
  • a to z
  • underscore (_).

Input with mixed cased words are disallowed. Examples of disallowed cases:

  • Coding_Convention_Conversion
  • a_BC

Example Cases

Input                        | Expected Output
===========================================================
CodingConventionConversion   | coding_convention_conversion
coding_convention_conversion | CodingConventionConversion
abc                          | Abc
Abc                          | abc
ABC                          | a_b_c
a_b_c                        | ABC
a                            | A
A                            | a

Rules

  • It is allowed to use ToUpper, ToLower and ToTitleCase functions.
  • Using regular expressions is allowed.
  • : shortest code in bytes wins!
share|improve this question
    
Is using a ToTitleCase function okay? You didn't specify, so I'd assume it is okay. – Justin Jan 26 at 6:55
    
@Justin: Good question indeed. Let's make it more fun and disallow the ToTitleCase function :) – Dariusz Woźniak Jan 26 at 7:04
    
Darn... my solution relies on it – Justin Jan 26 at 7:06
    
@Justin: Okay - I didn't specify it in the beginning, so in that case - let's allow it anyway. – Dariusz Woźniak Jan 26 at 7:08

12 Answers 12

up vote 3 down vote accepted

Pyth, 25 bytes 29 33 35 40

Saved 2 bytes thanks to @Dennis

Saved 4 bytes thanks to @FryAmTheEggman

?rIz0smrd4cz\_tsXzrG1*\_G

Try it online

share|improve this answer
    
Your link needs to be updated. – isaacg Jan 26 at 6:36
    
When I try put "abc" as an input, it yields "bc" as an output. Bug? :) – Dariusz Woźniak Jan 26 at 9:39
    
To fix what @DariuszWoźniak noticed, you can change your condition from /z\_ to rIz0. I also believe I found a same-length alternative to the adding underscores program: tsXzrG1_Mcj\_G2, maybe someone can golf it more... – FryAmTheEggman Jan 26 at 18:16
    
Ah, found it: tsXzrG1*\_G – FryAmTheEggman Jan 26 at 18:29

Jolf, 35 bytes

Saves 1 byte thanks to @Cᴏɴᴏʀ O'Bʀɪᴇɴ. This is encoded in ISO 8859-7.

? hI'_ΜGI'_dpyH0pxRGIL0"(?=[A-Z])'_

Woohoo my first Jolf program!

Explanation

   // I = input
? hI'_                              // If input contains _
       GI'_                          // Split on _
      Μ    d                         // Loop, then join
            pyH0                     // Make the first character uppercase
                                    // ELSE...
                  RGIL0"(?=[A-Z])    // Split *after* all uppercase chars
                                 '_  // join with _ 
                px                   //Make lowercase

Try it online

share|improve this answer
    
You can use string separation at the end, so it becomes "(?=[A-Z])'_. The string is closed automatically. – Cᴏɴᴏʀ O'Bʀɪᴇɴ Jan 26 at 0:54
    
@CᴏɴᴏʀO'Bʀɪᴇɴ oh, cool, thanks! – Downgoat Jan 26 at 0:55

Retina, 37

Thanks to @ MartinBüttner for saving 4 bytes!

^|[A-Z]
_$0
T`Ll`lL`_.
^_|_(?=[A-Z])

(Note the trailing newline.)

Try it online. Note this includes extra m` to configure a couple of lines to treat each input line separately so all testcases may be run in one go. This is not a requirement of the question, so these are not counted in the score.

  • Lines 1 and 2 insert _ either at the beginning of input or before uppercase letters. All words are now _-separated, regardless of case.
  • Line 3 swaps case of the first letter in each word.
  • Lines 4 and 5 remove _ either at the start of input, or when followed by an uppercase letter.
share|improve this answer
    
This saves four bytes: retina.tryitonline.net/… – Martin Ender Jan 26 at 7:43
    
Also you can avoid the trailing empty line by omitting the last ?= and replacing that stage with $1 (doesn't affect the byte count though). – Martin Ender Jan 26 at 7:44
    
@Martin Very good - thanks! – Digital Trauma Jan 26 at 16:11

GNU Sed, 46

Thanks to @TobySpeight for saving 2 bytes!

Score includes +1 for -E (or -r) option to sed.

s/(^|_)([a-z])/\u\2/g
t
s/[A-Z]/_\l&/g
s/^_//

Try it online.

Fairly straightforward sed:

  • Line 1 substitutes beginning of line or _, followed by a lowercase letter with the upper case of that letter. The g flag to s performs this substitution for each instance found
  • t jumps to the : unnamed label if there were any matches for the above substitution. This label is implicitly at the end.
  • Otherwise all uppercase letters are substituted with _ the lower case of that letter
  • This leaves a leading _ before the first letter. s/^_// removes that.
share|improve this answer
1  
@Toby Thanks. -E works in my GNU sed 4.2.2 (Ubuntu 14.04.3), though its not in the man page. I read somewhere [citation needed] that -E is newer Posix option that will officially be added to GNU Sed in a newer release, but is already there unofficially. Regardless, -r does the right thing if -E doesn't work for you. – Digital Trauma Jan 26 at 16:19
    
@Toby lines 280-282 of sed/sed.c are /* Undocumented, for compatibility with BSD sed. */ case 'E': case 'r':. – Digital Trauma Jan 26 at 17:00
    
@Digital - I was mistaken; my sed does accept -E as a synonym for -r. I wasn't correctly passing a minimal program e.g. sed -E -e Q – Toby Speight Jan 26 at 18:03

JavaScript (ES6), 87 bytes

s=>s.replace(/[A-Z]|(^|_)(.)/g,(c,_,l,i)=>l?l.toUpperCase():(i?"_":"")+c.toLowerCase())

Explanation

Depending on which part of the regex matched, it replaces the match with the opposite case.

s.replace(
  /[A-Z]|(^|_)(.)/g,
  (c,_,l,i)=>
    l?
      (i?"_":"")+c.toLowerCase()
    :l.toUpperCase()
)

Test

var solution = s=>s.replace(/[A-Z]|(^|_)(.)/g,(c,_,l,i)=>l?l.toUpperCase():(i?"_":"")+c.toLowerCase())
<input type="text" id="input" value="coding_convention_conversion" />
<button onclick="result.textContent=solution(input.value)">Go</button>
<pre id="result"></pre>

share|improve this answer

Ruby, 101 87 75 bytes

->s{s.gsub(/^.|[A-Z]/,'_\0').gsub(/_./,&:swapcase).gsub(/_(?=[A-Z])|^_/,'')}

Unfortunately, this does exactly the same thing as the Retina solution, as that method ended up being shorter than anything else I came up with.

share|improve this answer

Python 3, 130 bytes

Quick and dirty attempt using regex to split at the caps. Pretty brute force: if anyone can come up with a different approach I'm sure this can be beaten.

import re
lambda s:('_'.join(re.findall('[A-Z][a-z]*',s)).lower(),''.join([a[0].upper()+a[1:]for a in s.split('_')]))[s.islower()]
share|improve this answer

PHP 160 bytes

not the shortest but for completeness here my solution in PHP, $s holds the string to convert:

trim(preg_replace_callback('/((^[a-z]|_[a-z])|([A-Z]))/',function($m){return empty($m[2])?'_'.strtolower($m[3]):strtoupper(str_replace('_','',$m[2]));},$s),'_')
share|improve this answer
1  
Welcome to Programming Puzzles and Code Golf Stack Exchange. Well done for posting something in a language that you knew wasn't going to win. code-golf challenges are mostly within languages, so using a non-golfing language is good. +1 d:-D – wizzwizz4 Jan 28 at 17:04

Perl 6,  73 72 71  68 bytes

{.comb(/<:Lu><:Ll>*|<:Ll>+/).map({/<:Lu>/??.lc!!.tc}).join('_'x?/<:Lu>/)} # 73
{.comb(/<:Lu><:Ll>*|<:L>+/).map({/<:Lu>/??.lc!!.tc}).join('_'x?/<:Lu>/)}  # 72
{/<:Lu>/??S:g/(^)?(<:Lu>)/{$0||'_'}$1.lc()/!!S:g/[^|_](<:Ll>)/$0.tc()/}   # 71
{.comb(/<:Lu><:Ll>*|<:L>+/).map({/<:Lu>/??.lc!!.tc}).join('_'x!/_/)}      # 68

Usage:

# give it a lexical name
my &code = {...}

for <CodingConventionConversion coding_convention_conversion abc Abc ABC a_b_c a A>
{ say .&code }
coding_convention_conversion
CodingConventionConversion
Abc
abc
a_b_c
ABC
A
a

Explanation:

{
  .comb( / <:Lu><:Ll>* | <:L>+ / ) # grab the "words" only
  .map({
      /<:Lu>/ # if the word has uppercase
    ??
      .lc     # lowercase the whole word
    !!
      .tc     # otherwise titlecase the word
   })
  .join(  # join the words
    '_'   # with '_'
    x     # repeated
    !/_/  # zero times if it had a _, otherwise once
  )
}

You may be wondering why I used the Unicode properties (<:Lu>, <:Ll>) instead of just a character class. In Perl 6 they are no longer spelled [a-z] they are spelled <[a..z]> which is 1.6 times as big. The brackets [ … ] are used for non-capturing grouping instead which was spelled as (?: … ) in Perl 5.

share|improve this answer

Japt, 40 bytes

UfV="%A" ?UrV@'_s!Y +Xv} :Ur"^.|_."_sJ u

Test it online!

How it works

           // Implicit: U = input string
UfV="%A"   // Set variable V to the string "\\A", and get all matches in U.
?          // If the list is not null:
UrV@     } //  Replace each match X and its index Y with this function:
'_s!Y +Xv  //   Return "_".slice(!Y) (1 for Y=0, 0 for anything else) + X.toLowerCase().
:          // Otherwise:
Ur"^.|_."  //  Replace the char at the beginning and each char following an underscore with:
_sJ u      //   The last char of the match (the letter) .toUpperCase().
share|improve this answer

Perl 5, 42 bytes

40 bytes plus 2 for -p (thanks, dev-null)

s/[A-Z]/_\l$&/g||s/(^|_)(.)/\u$2/g;s/_//
share|improve this answer
    
On Windows, using perl and MINGW32, I get no output, what am I missing? – ChatterOne Jan 27 at 21:46
    
@ChatterOne I don't know what MINGW32 is, but it worked fine for me on Strawberry Perl. Use -E instead of -e. – msh210 Jan 27 at 21:49

𝔼𝕊𝕄𝕚𝕟 3, 15 chars / 32 bytes (noncompetitive)

⟮ѨDZï⟯≠ï?Ⅰ:ѨȎѨƎï

Try it here (Firefox only).

v3 was released after this challenge, with a bunch of bugfixes and library updates.

Explanation

This is just a mashup of builtins.

⟮ѨDZï⟯≠ï?Ⅰ:ѨȎѨƎï // implicit: ï=input
⟮ѨDZï⟯≠ï?        // check if ï is NOT in snake_case
       Ⅰ       // if so, then convert to snake_case
        :ѨȎѨƎï // otherwise, convert to camelCase and make the first letter UPPERCASE
share|improve this answer

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.