211

I’ve been trying to get a JavaScript regex command to turn something like "thisString" into "This String" but the closest I’ve gotten is replacing a letter, resulting in something like "Thi String" or "This tring". Any ideas?

To clarify I can handle the simplicity of capitalizing a letter, I’m just not as strong with RegEx, and splitting "somethingLikeThis" into "something Like This" is where I’m having trouble.

Sebastian Simon
  • 18,263
  • 7
  • 55
  • 75
A Wizard Did It
  • 3,614
  • 4
  • 28
  • 32
  • 7
    How is this a duplicate of that. All that does is capitalize the first character in a string, nothing close to what I want to do. – A Wizard Did It Nov 10 '10 at 21:36
  • Hmm its not a dupe of the question, but the result might be the same. Or is that not what you wanted to do ? Elaborate more ? – superfro Nov 10 '10 at 21:38
  • For regex practice I suggest RegExr or Expresso to test in and just look at all the regex questions on SO and try to answer them. Regexs are not the simplest thing in the world, but just remember that if your regex is confusing YOU then split it up and work in pieces. – josh.trow Nov 10 '10 at 21:42

12 Answers12

472
"thisStringIsGood"
    // insert a space before all caps
    .replace(/([A-Z])/g, ' $1')
    // uppercase the first character
    .replace(/^./, function(str){ return str.toUpperCase(); })

displays

This String Is Good

(function() {

  const textbox = document.querySelector('#textbox')
  const result = document.querySelector('#result')
  function split() {
      result.innerText = textbox.value
        // insert a space before all caps
        .replace(/([A-Z])/g, ' $1')
        // uppercase the first character
        .replace(/^./, (str) => str.toUpperCase())
    };

  textbox.addEventListener('input', split);
  split();
}());
#result {
  margin-top: 1em;
  padding: .5em;
  background: #eee;
  white-space: pre;
}
<div>
  Text to split
  <input id="textbox" value="thisStringIsGood" />
</div>

<div id="result"></div>
Vincent Robert
  • 35,564
  • 14
  • 82
  • 119
  • 1
    Good man, splitting it up. Just remember Bobince's advice : http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454 – josh.trow Nov 10 '10 at 21:49
  • Are you sure this is compatible with IE? Just tried in IETester7 & got an error. – strongriley Aug 22 '11 at 22:06
  • Not tested in IE but I see no reason why it should not work :-/ – Vincent Robert Aug 26 '11 at 08:18
  • To add onto this answer, if your string has numbers in it you can add `.replace(/([a-z])(?=[0-9])/g, '$1 ')` to format them correctly – challett Dec 10 '15 at 16:48
  • 4
    Also adding: if you have an all caps acronym that you want to keep together you can change the first regex to "/([A-Z][a-z])/" – AaronLight Jun 08 '16 at 00:10
  • 2
    "This" -> " This" (unwanted prefix space). Maybe change it to: str.slice(0, 1).toUpperCase() + str.slice(1).replace(/([A-Z])/g, ' $1') – Mark Vayngrib Jun 11 '17 at 20:29
  • I need help on a specific case. How do make 'userID' into 'User ID'? The current solution will result to 'User I D'. And currently I just added `.replace('I D', 'ID')` to solve the problem. But how do I do it dynamically where it would check first if the upper case is not preceded by another upper case before adding a space before it? – Alex Pappas Dec 19 '18 at 11:43
  • 6
    @ColdCerberus You can use: `str.replace(/((?<!^)[A-Z](?![A-Z]))(?=\S)/g, ' $1').replace(/^./, s => s.toUpperCase() );` It will convert `userID` to `User ID`, and it will even convert `userIDField` to `User ID Field` – Eugene Mala Dec 01 '19 at 14:28
  • Apparently, it results to "UserID Field" – Alex Pappas Dec 17 '19 at 08:37
99

I had an idle interest in this, particularly in handling sequences of capitals, such as in xmlHTTPRequest. The listed functions would produce "Xml H T T P Request" or "Xml HTTPRequest", mine produces "Xml HTTP Request".

function unCamelCase (str){
    return str
        // insert a space between lower & upper
        .replace(/([a-z])([A-Z])/g, '$1 $2')
        // space before last upper in a sequence followed by lower
        .replace(/\b([A-Z]+)([A-Z])([a-z])/, '$1 $2$3')
        // uppercase the first character
        .replace(/^./, function(str){ return str.toUpperCase(); })
}

There's also a String.prototype version in a gist.

Matt Wiebe
  • 1,091
  • 7
  • 3
  • 1
    The same can be achieved with 2 replace calls: `str.replace(/((?<!^)[A-Z](?![A-Z]))(?=\S)/g, ' $1').replace(/^./, s => s.toUpperCase() )` – Eugene Mala Dec 01 '19 at 14:32
27

This can be concisely done with regex lookahead (live demo):

function splitCamelCaseToString(s) {
    return s.split(/(?=[A-Z])/).join(' ');
}

(I thought that the g (global) flag was necessary, but oddly enough, it isn't in this particular case.)

Using lookahead with split ensures that the matched capital letter is not consumed and avoids dealing with a leading space if UpperCamelCase is something you need to deal with. To capitalize the first letter of each, you can use:

function splitCamelCaseToString(s) {
    return s.split(/(?=[A-Z])/).map(function(p) {
        return p.charAt(0).toUpperCase() + p.slice(1);
    }).join(' ');
}

The map array method is an ES5 feature, but you can still use it in older browsers with some code from MDC. Alternatively, you can iterate over the array elements using a for loop.

PleaseStand
  • 31,641
  • 6
  • 68
  • 95
22

I think this should be able to handle consecutive uppercase characters as well as simple camelCase.

For example: someVariable => someVariable, but ABCCode != A B C Code.

The below regex works on your example but also the common example of representing abbreviations in camcelCase.

"somethingLikeThis"
    .replace(/([a-z])([A-Z])/g, '$1 $2')
    .replace(/([A-Z])([a-z])/g, ' $1$2')
    .replace(/\ +/g, ' ') => "something Like This"

"someVariableWithABCCode"
    .replace(/([a-z])([A-Z])/g, '$1 $2')
    .replace(/([A-Z])([a-z])/g, ' $1$2')
    .replace(/\ +/g, ' ') => "some Variable With ABC Code"

You could also adjust as above to capitalize the first character.

thegreenpizza
  • 1,440
  • 13
  • 8
20

Lodash handles this nicely with _.startCase()

Chiramisu
  • 4,687
  • 7
  • 47
  • 77
Lawrence Chang
  • 459
  • 5
  • 7
14
function spacecamel(s){
    return s.replace(/([a-z])([A-Z])/g, '$1 $2');
}

spacecamel('somethingLikeThis')

// returned value: something Like This

kennebec
  • 102,654
  • 32
  • 106
  • 127
  • 1
    Nice one! this is exactly what i needed i wanted to split eg: DiscoveryChannel and HBO other answers gave me Discovery Channel and H B O, but your answer did the trick for me as HBO stayed intact thank you! – AJS Feb 11 '16 at 06:31
  • I always love one line solutions like these – penduDev Sep 19 '20 at 10:16
6

A solution that handles numbers as well:

function capSplit(str){
   return str.replace(
      /(^[a-z]+)|[0-9]+|[A-Z][a-z]+|[A-Z]+(?=[A-Z][a-z]|[0-9])/g,
      function(match, first){
          if (first) match = match[0].toUpperCase() + match.substr(1);
          return match + ' ';
          }
       )
   }

Tested here [JSFiddle, no library. Not tried IE]; should be pretty stable.

SamGoody
  • 13,758
  • 9
  • 81
  • 91
  • Only one in a long list which correctly handles numbers: "BrochureUSA1999" to "Brochure USA 1999". – DaveG Apr 08 '22 at 00:57
2

Try this solution here -

var value = "myCamelCaseText";
var newStr = '';
for (var i = 0; i < value.length; i++) {
  if (value.charAt(i) === value.charAt(i).toUpperCase()) {
    newStr = newStr + ' ' + value.charAt(i)
  } else {
    (i == 0) ? (newStr += value.charAt(i).toUpperCase()) : (newStr += value.charAt(i));
  }
}
return newStr;
M3ghana
  • 1,231
  • 1
  • 9
  • 19
0

If you don't care about older browsers (or don't mind using a fallback reduce function for them), this can split even strings like 'xmlHTTPRequest' (but certainly the likes of 'XMLHTTPRequest' cannot).

function splitCamelCase(str) {
        return str.split(/(?=[A-Z])/)
                  .reduce(function(p, c, i) {
                    if (c.length === 1) {
                        if (i === 0) {
                            p.push(c);
                        } else {
                            var last = p.pop(), ending = last.slice(-1);
                            if (ending === ending.toLowerCase()) {
                                p.push(last);
                                p.push(c);
                            } else {
                                p.push(last + c);
                            }
                        }
                    } else {
                        p.push(c.charAt(0).toUpperCase() + c.slice(1));
                    }
                    return p;
                  }, [])
                  .join(' ');
}
0

My version

function camelToSpace (txt) {
  return txt
    .replace(/([^A-Z]*)([A-Z]*)([A-Z])([^A-Z]*)/g, '$1 $2 $3$4')
    .replace(/ +/g, ' ')
}
camelToSpace("camelToSpaceWithTLAStuff") //=> "camel To Space With TLA Stuff"
pykiss
  • 949
  • 12
  • 15
0
const value = 'camelCase';
const map = {};
let index = 0;
map[index] = [];
for (let i = 0; i < value.length; i++) {
  if (i !== 0 && value[i] === value[i].toUpperCase()) {
    index = i;
    map[index] = [];
  }
  if (i === 0) {
    map[index].push(value[i].toUpperCase());
  } else {
    map[index].push(value[i]);
  }
}
let resultArray = [];
Object.keys(map).map(function (key, index) {
  resultArray = [...resultArray, ' ', ...map[key]];
  return resultArray;
});
console.log(resultArray.join(''));
kob003
  • 2,206
  • 2
  • 12
  • 19
-6

Not regex, but useful to know plain and old techniques like this:

var origString = "thisString";
var newString = origString.charAt(0).toUpperCase() + origString.substring(1);
Mohammed Sajid
  • 4,778
  • 2
  • 15
  • 20
rob
  • 9,933
  • 7
  • 42
  • 73