Convert camelCase and PascalCase to Title Case I'm trying to take camelCase and PascalCase strings into a function and spit them out as Title Case. This function also needs to be able to handle odd PascalCase strings with capitalized abbreviations such as "CDReceiverBox" and return a readable string - "CD Receiver Box". 

My current working solution:

function splitCamelCase(camelCaseString) {
    const result = camelCaseString
        .replace(/([A-Z][a-z])/g, " $1")
        .replace(/([A-Z]+)/g, " $1")
        .replace(/ +/g, " ")
        .replace(/^ +/g, "");

    return result.charAt(0).toUpperCase() + result.slice(1);
}


I would like to condense the amount of replace statements I'm using by at least combining the first two replace statements and the last two together since they are semi similar. The more concise I can make this the better.

CodePen: https://codepen.io/andrewgarrison/pen/dEQrMy
I like your solution quite a bit. It's clear, easy to read and I don't see any bugs. 

There are many ways to condense the replace calls as you mention, but I think you're at a point where such changes can easily have a disproportionate impact on readability. That's good--it means the code is already pretty optimal from that standpoint.

For example, here's a one-shot replace using alternation, but its merit is debatable:

const splitCamelCase = s =&gt; s.replace(
    /^[a-z]|^([A-Z]+)(?=[A-Z]|$)|([A-Z])+(?=[A-Z]|$)|([A-Z])(?=[a-z]+)/g,
    m =&gt; " " + m.toUpperCase()
  ).trim()
;


The idea here is to enumerate each scenario, join the patterns with |s, and provide an arrow function to handle the addition of a space and a capital letter for each match.

With the two extremes in mind, I prefer a balanced approach such as:

const splitCamelCase = s =&gt;
  s.replace(/([A-Z][a-z])/g, " $1")
   .replace(/\s*([A-Z]+)/g, " $1")
   .replace(/./, m =&gt; m.toUpperCase())
   .trim()
;


or perhaps

const splitCamelCase = s =&gt;
  s.replace(/([A-Z][a-z]|[A-Z]+(?=[A-Z]|$))/g, " $1")
   .replace(/./, m =&gt; m.toUpperCase())
   .trim()
;


These should offer ideas as far as how far you want to go in making the succinctness versus readability tradeoff. But, failing the possibility of a shortcut I might have overlooked, keeping your code basically as-is seems like a fine option to me.

If it's performance you're after in reducing replace calls, there's no guarantee that fewer calls will translate into better performance. Under the hood, the regex engine may make more passes to compensate; you can benchmark and tweak using a debugger like regex101. For performance, it's likely best to avoid regex entirely and write a single-pass loop by hand.

Here's a test runner:



const splitCamelCase = s =&gt;
  s.replace(/([A-Z][a-z]|[A-Z]+(?=[A-Z]|$))/g, " $1")
   .replace(/./, m =&gt; m.toUpperCase())
   .trim()
;

[
  "AAABbbbbCcDddEEFffGGHhIiJ",
  "AaBbCcDDEeFGgHHHH",
  "CDBoomBoxAAAABbbbCCC",
  "CDBoomBox",
  "camelCase",
  "camel",
  "Camel",
  "c",
  "C",
  "Aa",
  "AA",
  "aa",
  "AAA",
  "aB", 
  "aBC",
  "aBCc",
  "",
].forEach(test =&gt; 
  console.log(
    splitCamelCaseOriginal(test) === splitCamelCase(test) 
      ? `'${test}' -&gt; '${splitCamelCase(test)}'` 
      : "TEST FAILED"
  )
);

function splitCamelCaseOriginal(camelCaseString) {
    const result = camelCaseString
        .replace(/([A-Z][a-z])/g, " $1")
        .replace(/([A-Z]+)/g, " $1")
        .replace(/ +/g, " ")
        .replace(/^ +/g, "");

    return result.charAt(0).toUpperCase() + result.slice(1);
}