6

I have a string that is in ALL caps originally and I want it to be title case:

THIS IS MY STRING WHY AM I YELLLING?

And I want it to be:

This Is My String Why Am I Yelling?

I can't use css text-transform:capitalize when the letters are in CAPS initially. So I know I have to use JS. I tried this, which works but I'm not sure it's very efficient:

 $('.location').each(function () {

    var upper = $(this).html();
    var lower = upper.toLowerCase();
    $(this).replaceWith(lower); 

});

And now that my letters are actually lowercase, I use CSS text-transform:capitalize.

Is there a more efficient way to do this? (I'm already using jQuery on the site, so that's why I've used it above.)

Thanks!

LBF
  • 1,133
  • 2
  • 14
  • 39

5 Answers5

8

You could match consecutive word characters, and use a replacer function to replace with the first character (as-is), followed by the rest with toLowerCase() called on them:

const text = 'THIS IS MY STRING WHY AM I YELLLING?';
const output = text.replace(
  /(\w)(\w*)/g,
  (_, firstChar, rest) => firstChar + rest.toLowerCase()
);
console.log(output);
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • This one has the added benefit of not lowercasing the "c" in "WASHINGTON, D.C." I didn't list that as a requirement, but while testing this out, I noticed that this is the only one that happens to keep the "c" capitalized, like "Washington D.C." – LBF Apr 19 '19 at 04:37
  • Hey, so does mine! ;D It also *ensures* the first char is capitalized, just in case. – reergymerej Apr 19 '19 at 04:47
  • You're right! I wrote this before your answer came through. A few others have updated as well. I'm still testing everything out. Thank you! – LBF Apr 19 '19 at 04:53
  • Thank you. There are many good answers, and I don't know that I'm qualified to determine which is most efficient. I am going to choose this one as the answer because it is clean and simple, you were first, and it has the most upvotes so perhaps someone smarter than me knows best. :) – LBF Apr 19 '19 at 05:17
2

Another possible solution could be using the regular expression /./g in String.replace() and check on the replacement function if the previous character, of the current matched one, is a letter and the offset of this one is not zero, to decide whether to replace the character by the lower-case or upper-case version.

let str = "THIS IS MY STRING WHY AM I YELLLING. WASHINGTON D.C?";

let out = str.replace(/./g, (m, offset, str) =>
{
    return (offset !== 0 && /\w/.test(str[offset-1])) ? m.toLowerCase() : m.toUpperCase();
});

console.log(out);
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}
Shidersz
  • 16,846
  • 2
  • 23
  • 48
  • Thanks for the edit. This worked well. I chose another answer simply because the code itself was simpler for me to understand. Hopefully someone with more experience than me can provide a verdict on what's actually most efficient. – LBF Apr 19 '19 at 05:20
  • @LBF It is ok, the accepted answer would be the one I would choice too. – Shidersz Apr 19 '19 at 05:35
2

const s = 'THIS IS MY STRING, from WaShInGtOn D.C. WHY AM I YELLLING?'
const result = s.replace(/([a-z])([a-z]*)/gi, (_, p1, p2) => 
  p1.toUpperCase() + p2.toLowerCase()
)
console.log(result)

Use simple regex and capture groups in String.replace. When capturing, you can access the groups as described here on MDN.

I don't know if this is the most efficient, but it is pretty simple (ie easy for future devs to grok).

Community
  • 1
  • 1
reergymerej
  • 2,371
  • 2
  • 26
  • 32
  • 1
    I like this answer, and though I chose the other one, I upvoted because this one is so close and it's very clean. Thanks for your time! – LBF Apr 19 '19 at 05:19
1

This is a solution split by space and handle each array item.

var str = 'THIS IS MY STRING WHY AM I YELLLING?';
var arr = str.split(' ');
var result = arr.map(c=> c.charAt(0) + c.toLowerCase().slice(1));
str = result.join(' ')
console.log(str)

var str = 'THIS IS MY STRING WHY AM I YELLLING?';
var arr = str.split(' ');
var result = arr.map(c=> c.charAt(0) + c.toLowerCase().slice(1));
str = result.join(' ')
console.log(str)
Hien Nguyen
  • 24,551
  • 7
  • 52
  • 62
  • Thanks! I like having a regex alternative. I'm still trying to figure that out. – LBF Apr 19 '19 at 05:20
0

I use this PHP-equivalent function:

function ucwords(str) {
  var words = str.split(' ');
  str = '';
  for (var i = 0; i < words.length; i++) {
    var word = words[i];
    word = word.charAt(0).toUpperCase() + word.slice(1);
    if (i > 0) {
      str = str + ' ';
    }
    str = str + word;
  }
  return str;
}

$(document).ready(function() {
  $('p').each(function() {
    $(this).text(ucwords($(this).text()));
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<p>this is all lowercase text</p>
<p>THIS IS ALL UPPERCASE TEXT</p>

As you can see, this does not change uppercase letters to lowercase. If you want to force title case on all words, I use this:

function toTitleCase(str) {
  return str.replace(/\w\S*/g, function(txt) {
    return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
  });
}

$(document).ready(function() {
  $('p').each(function() {
    $(this).text(toTitleCase($(this).text()));
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<p>this is all lowercase text</p>
<p>THIS IS ALL UPPERCASE text</p>
Jay
  • 353
  • 4
  • 8