JavaScript Convert Names to Uppercase, Except Mc/Mac/etc - javascript

Everything I can find by searching is people wanting to convert to sentence/title case from lower/upper/random case. That's the opposite of my problem.
What I have is already correct, I want to convert it to uppercase except for the "c" or "ac" etc. So McDonald becomes McDONALD, MacDonald becomes MacDONALD, etc.
Probably the best way is separating out the lower-case letters that occur between two upper-case letters, either before or after running toUpperCase(), but my brain is fried at the moment so I'm not sure how to go about it.
It's for an After Effects expression, controlling the display so I can have sentence case in one composition and upper case in another, from the same source layer. So I know input will be perfect.

You can try something like this:
const input = "MacDonald";
const matches = input.match(/([A-Z][a-z]*)/g);
const output = matches.length > 1 ?
matches.reduce((acc, match, index) => {
if (index === 0) {
return match;
}
return acc + match.toUpperCase();
}) :
input.toUpperCase();
First we take the input apart by matching it against a simple regular expression. The match method in the example will return ["Mac","Donald"].
Then, if there is only one match, we return it in uppercase.
In case of multiple matches, we construct the result by concatenating uppercase parts except for the first part.
Here's a version for a whole sentence:
const input = "Old MacDonald is a fine man.";
const output = input
.split(/\s/)
.map(word => {
const matches = word.match(/([A-Z][a-z]*)/g);
if (!matches || matches.length === 1) {
return word.toUpperCase();
}
return matches.reduce((acc, match, index) => {
return index === 0 ? match : acc + match.toUpperCase();
});
})
.join(' ');
// output == "OLD MacDONALD IS A FINE MAN."

Sami Hult's answer covers most of the bases, but unfortunately refuses to work in After Effects due to syntax issues and map() and reduce() not being supported, and I wanted to make one small tweak, all-capsing only the last portion rather than all but the first (to account for a possible double prefix).
So based on that code, I came up with this:
function str_uppercase(str) {
str = str.split(/\s/);
var output = [];
for (i = 0; i < str.length; i++) {
var word = str[i];
var matches = word.match(/([A-Z][a-z]*)/g);
if (!matches || matches.length === 1) {
word = word.toUpperCase();
} else {
var x = matches.length - 1;
matches[x] = matches[x].toUpperCase();
word = matches.join('');
}
output.push(word);
}
return output.join(' ');
}
console.log(str_uppercase('Old MacMcDonald Had a farm'));
// => OLD MacMcDONALD HAD A FARM

The code below assumes a string prefix to be one capital letter character followed by one or more small letter characters followed by one capital letter character and always at the beginning of the whole word.
The prefix will be retained as it is and the rest will be capitalized.
const input = [
"McDonald",
"MacDonald",
"Mcdonald",
"mcDonald",
"mcdonald"
];
// Function for converting to special uppercase
const specialUpperCase = function(item) {
// Find prefix (one or more lower case characters between upper case character - at the beginning)
const match = item.match(/^[A-Z][a-z]+[A-Z]/);
if (match) {
// If prefix, capitalize only the remaining
return match[0] + item.substr(match[0].length).toLocaleUpperCase();
}
// If no prefix, capitalize the whole string
return item.toLocaleUpperCase();
};
const output = input.map(specialUpperCase);
console.log(output);

The easiest solution would probably be to keep a list of prefixes and test if the word starts with one of these:
//Prefixes to look for
var prefixToKeep = [
"Mac",
"Mc"
];
//Selective uppercase function
function selectiveUpperCase(text) {
//Find words by wordBoundaries
return text.replace(/\b\w+\b/gim, function (word) {
//Test for prefixes
for (var prefixToKeepIndex = 0; prefixToKeepIndex < prefixToKeep.length; prefixToKeepIndex++) {
var prefix = prefixToKeep[prefixToKeepIndex];
if (word.indexOf(prefix) === 0) {
//prefix matches. Return prefix as is + rest of the word in uppercase
return word.slice(0, prefix.length) + word.slice(prefix.length).toUpperCase();
}
}
//No prefix found, return word as uppercase
return word.toUpperCase();
});
}
//TEST
var text = "Old MacDonald had a farm\nE-I-E-I-O\nAnd on this farm he had a cow\nE-I-E-I-O\nWith a moo-moo here\nAnd a moo-moo there\nHere a moo, there a moo\nEverywhere a moo-moo\nOld MacDonald had a farm\nE-I-E-I-O ";
console.log(selectiveUpperCase(text));
EDIT 1 - Upper-Lower-Upper Test
In response to the comments, this newer version tests for Upper-Lower-Upper cases and uses its findings to determine which parts to uppercase.
//Selective uppercase function
function selectiveUpperCase(text) {
//Find words by wordBoundaries
return text.replace(/\b\w+\b/gim, function (word) {
var reg = /[A-Z]+[a-z]+[A-Z]\w+/gm;
//Test for Upper-Lower-Upper combo
if (reg.test(word) || reg.test(word)) {
//start at index 1
var l = 0;
while (l++ < word.length) {
//move up the word and test for an uppercase letter
if (word[l] === word[l].toUpperCase()) {
break;
}
l++;
//return the first slice (the prefix) as is and uppercase the rest
return word.slice(0, l) + word.slice(l).toUpperCase();
}
}
//No prefix found, return word as uppercase
return word.toUpperCase();
});
}
//TEST
var text = "Old MacDonald had a farm\nE-I-E-I-O\nAnd on this farm he had a cow\nE-I-E-I-O\nWith a moo-moo here\nAnd a moo-moo there\nHere a moo, there a moo\nEverywhere a moo-moo\nOld McDonald had a farm\nE-I-E-I-O ";
console.log(selectiveUpperCase(text));

ES6 version with RegEx, you can try below function replaceStr()
const replaceStr = str => str.replace(/(^[A-Z])([a-z]{1,2})(.+)/,
(_, p1, p2, p3) => p1.toUpperCase() + p2 + p3.toUpperCase());

Related

Is There any any javascript (js) function for capitalizing string? [duplicate]

I'm trying to write a function that capitalizes the first letter of every word in a string (converting the string to title case).
For instance, when the input is "I'm a little tea pot", I expect "I'm A Little Tea Pot" to be the output. However, the function returns "i'm a little tea pot".
This is my code:
function titleCase(str) {
var splitStr = str.toLowerCase().split(" ");
for (var i = 0; i < splitStr.length; i++) {
if (splitStr.length[i] < splitStr.length) {
splitStr[i].charAt(0).toUpperCase();
}
str = splitStr.join(" ");
}
return str;
}
console.log(titleCase("I'm a little tea pot"));
You are not assigning your changes to the array again, so all your efforts are in vain. Try this:
function titleCase(str) {
var splitStr = str.toLowerCase().split(' ');
for (var i = 0; i < splitStr.length; i++) {
// You do not need to check if i is larger than splitStr length, as your for does that for you
// Assign it back to the array
splitStr[i] = splitStr[i].charAt(0).toUpperCase() + splitStr[i].substring(1);
}
// Directly return the joined string
return splitStr.join(' ');
}
document.write(titleCase("I'm a little tea pot"));
You are making complex a very easy thing. You can add this in your CSS:
.capitalize {
text-transform: capitalize;
}
In JavaScript, you can add the class to an element
document.getElementById("element").className = "capitalize";
ECMAScript 6 version:
const toTitleCase = (phrase) => {
return phrase
.toLowerCase()
.split(' ')
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
.join(' ');
};
let result = toTitleCase('maRy hAd a lIttLe LaMb');
console.log(result);
Shortest One Liner (also extremely fast):
text.replace(/(^\w|\s\w)/g, m => m.toUpperCase());
Explanation:
^\w : first character of the string
| : or
\s\w : first character after whitespace
(^\w|\s\w) Capture the pattern.
g Flag: Match all occurrences.
If you want to make sure the rest is in lowercase:
text.replace(/(^\w|\s\w)(\S*)/g, (_,m1,m2) => m1.toUpperCase()+m2.toLowerCase())
Example usage:
const toTitleCase = str => str.replace(/(^\w|\s\w)(\S*)/g, (_,m1,m2) => m1.toUpperCase()+m2.toLowerCase())
console.log(toTitleCase("heLLo worLd"));
I think this way should be faster; cause it doesn't split string and join it again; just using regex.
var str = text.toLowerCase().replace(/(^\w{1})|(\s{1}\w{1})/g, match => match.toUpperCase());
Explanation:
(^\w{1}): match first char of string
|: or
(\s{1}\w{1}): match one char that came after one space
g: match all
match => match.toUpperCase(): replace with can take function, so; replace match with upper case match
If you can use a third-party library then Lodash has a helper function for you.
https://lodash.com/docs/4.17.3#startCase
_.startCase('foo bar');
// => 'Foo Bar'
_.startCase('--foo-bar--');
// => 'Foo Bar'
_.startCase('fooBar');
// => 'Foo Bar'
_.startCase('__FOO_BAR__');
// => 'FOO BAR'
<script src="https://cdn.jsdelivr.net/lodash/4.17.3/lodash.min.js"></script>
In ECMAScript 6, a one-line answer using the arrow function:
const captialize = words => words.split(' ').map( w => w.substring(0,1).toUpperCase()+ w.substring(1)).join(' ')
ECMAScript 6 version:
title
.split(/ /g).map(word =>
`${word.substring(0,1).toUpperCase()}${word.substring(1)}`)
.join(" ");
𝗙𝗮𝘀𝘁𝗲𝘀𝘁 𝗦𝗼𝗹𝘂𝘁𝗶𝗼𝗻 𝗙𝗼𝗿 𝗟𝗮𝘁𝗶𝗻-𝗜 𝗖𝗵𝗮𝗿𝗮𝗰𝘁𝗲𝗿𝘀
You could simply use a regular expression function to change the capitalization of each letter. With V8 JIST optimizations, this should prove to be the fast and memory efficient.
// Only works on Latin-I strings
'tHe VeRy LOOong StRINg'.replace(/\b[a-z]|['_][a-z]|\B[A-Z]/g, function(x){return x[0]==="'"||x[0]==="_"?x:String.fromCharCode(x.charCodeAt(0)^32)})
Or, as a function:
// Only works for Latin-I strings
var fromCharCode = String.fromCharCode;
var firstLetterOfWordRegExp = /\b[a-z]|['_][a-z]|\B[A-Z]/g;
function toLatin1UpperCase(x){ // avoid frequent anonymous inline functions
var charCode = x.charCodeAt(0);
return charCode===39 ? x : fromCharCode(charCode^32);
}
function titleCase(string){
return string.replace(firstLetterOfWordRegExp, toLatin1UpperCase);
}
According to this benchmark, the code is over 33% faster than the next best solution in Chrome.
𝗗𝗲𝗺𝗼
<textarea id="input" type="text">I'm a little tea pot</textarea><br /><br />
<textarea id="output" type="text" readonly=""></textarea>
<script>
(function(){
"use strict"
var fromCode = String.fromCharCode;
function upper(x){return x[0]==="'"?x:fromCode(x.charCodeAt(0) ^ 32)}
(input.oninput = function(){
output.value = input.value.replace(/\b[a-z]|['_][a-z]|\B[A-Z]/g, upper);
})();
})();
</script>
text-transform: capitalize;
CSS has got it :)
Also a good option (particularly if you're using freeCodeCamp):
function titleCase(str) {
var wordsArray = str.toLowerCase().split(/\s+/);
var upperCased = wordsArray.map(function(word) {
return word.charAt(0).toUpperCase() + word.substr(1);
});
return upperCased.join(" ");
}
I usually prefer not to use regexp because of readability and also I try to stay away from loops. I think this is kind of readable.
function capitalizeFirstLetter(string) {
return string && string.charAt(0).toUpperCase() + string.substring(1);
};
This routine will handle hyphenated words and words with apostrophe.
function titleCase(txt) {
var firstLtr = 0;
for (var i = 0;i < text.length;i++) {
if (i == 0 &&/[a-zA-Z]/.test(text.charAt(i)))
firstLtr = 2;
if (firstLtr == 0 &&/[a-zA-Z]/.test(text.charAt(i)))
firstLtr = 2;
if (firstLtr == 1 &&/[^a-zA-Z]/.test(text.charAt(i))){
if (text.charAt(i) == "'") {
if (i + 2 == text.length &&/[a-zA-Z]/.test(text.charAt(i + 1)))
firstLtr = 3;
else if (i + 2 < text.length &&/[^a-zA-Z]/.test(text.charAt(i + 2)))
firstLtr = 3;
}
if (firstLtr == 3)
firstLtr = 1;
else
firstLtr = 0;
}
if (firstLtr == 2) {
firstLtr = 1;
text = text.substr(0, i) + text.charAt(i).toUpperCase() + text.substr(i + 1);
}
else {
text = text.substr(0, i) + text.charAt(i).toLowerCase() + text.substr(i + 1);
}
}
}
titleCase("pAt o'Neil's");
// returns "Pat O'Neil's";
You can use modern JS syntax which can make your life much easier. Here is my code snippet for the given problem:
const capitalizeString = string => string.split(' ').map(item => item.replace(item.charAt(0), item.charAt(0).toUpperCase())).join(' ');
capitalizeString('Hi! i am aditya shrivastwa')
function LetterCapitalize(str) {
return str.split(" ").map(item=>item.substring(0,1).toUpperCase()+item.substring(1)).join(" ")
}
let cap = (str) => {
let arr = str.split(' ');
arr.forEach(function(item, index) {
arr[index] = item.replace(item[0], item[0].toUpperCase());
});
return arr.join(' ');
};
console.log(cap("I'm a little tea pot"));
Fast Readable Version see benchmark http://jsben.ch/k3JVz
ES6 syntax
const captilizeAllWords = (sentence) => {
if (typeof sentence !== "string") return sentence;
return sentence.split(' ')
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
.join(' ');
}
captilizeAllWords('Something is going on here')
Or it can be done using replace(), and replace each word's first letter with its "upperCase".
function titleCase(str) {
return str.toLowerCase().split(' ').map(function(word) {
return word.replace(word[0], word[0].toUpperCase());
}).join(' ');
}
titleCase("I'm a little tea pot");
Here a simple one-liner
const ucFirst = t => t.replace(/(^|\s)[A-Za-zÀ-ÖØ-öø-ÿ]/g, c => c.toUpperCase());
Note that it only changes case of first letter of every word, you might want to use it as so:
console.log(ucFirst('foO bAr'));
// FoO BAr
console.log(ucFirst('foO bAr'.toLowerCase()));
// Foo Bar
// works with accents too
console.log(ucFirst('éfoO bAr'));
// ÉfoO BAr
Or based on String.prototype here is one that handles several modes:
String.prototype.ucFirst = function (mode = 'eachWord') {
const modes = {
eachWord: /(^|\s)[A-Za-zÀ-ÖØ-öø-ÿ]/g,
firstWord: /(^|\s)[A-Za-zÀ-ÖØ-öø-ÿ]/,
firstChar: /^[A-Za-zÀ-ÖØ-öø-ÿ]/,
firstLetter: /[A-Za-zÀ-ÖØ-öø-ÿ]/,
};
if (mode in modes) {
return this.replace(modes[mode], c => c.toUpperCase());
} else {
throw `error: ucFirst invalid mode (${mode}). Parameter should be one of: ` + Object.keys(modes).join('|');
}
};
console.log('eachWord', 'foO bAr'.ucFirst());
// FoO BAr
console.log('eachWord', 'foO bAr'.toLowerCase().ucFirst());
// Foo Bar
console.log('firstWord', '1foO bAr'.ucFirst('firstWord'));
// 1foO BAr
console.log('firstChar', '1foO bAr'.ucFirst('firstChar'));
// 1foO bAr
console.log('firstLetter', '1foO bAr'.ucFirst('firstLetter'));
// 1FoO bAr
Edit:
Or based on String.prototype one that handles several modes and an optional second argument to specify word separators (String or RegExp):
String.prototype.ucFirst = function (mode = 'eachWord', wordSeparator = /\s/) {
const letters = /[A-Za-zÀ-ÖØ-öø-ÿ]/;
const ws =
'^|' +
(wordSeparator instanceof RegExp
? '(' + wordSeparator.source + ')'
: // sanitize string for RegExp https://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex#comment52837041_6969486
'[' + wordSeparator.replace(/[[{}()*+?^$|\]\.\\]/g, '\\$&') + ']');
const r =
mode === 'firstLetter'
? letters
: mode === 'firstChar'
? new RegExp('^' + letters.source)
: mode === 'firstWord' || mode === 'eachWord'
? new RegExp(
'(' + ws + ')' + letters.source,
mode === 'eachWord' ? 'g' : undefined
)
: undefined;
if (r) {
return this.replace(r, (c) => c.toUpperCase());
} else {
throw `error: ucFirst invalid mode (${mode}). Parameter should be one of: firstLetter|firstChar|firstWord|eachWord`;
}
};
console.log("mike o'hara".ucFirst('eachWord', " \t\r\n\f\v'"));
// Mike O'Hara
console.log("mike o'hara".ucFirst('eachWord', /[\s']/));
// Mike O'Hara
The function below does not change any other part of the string than trying to convert all the first letters of all words (i.e. by the regex definition \w+) to uppercase.
That means it does not necessarily convert words to Titlecase, but does exactly what the title of the question says: "Capitalize First Letter Of Each Word In A String - JavaScript"
Don't split the string
determine each word by the regex \w+ that is equivalent to [A-Za-z0-9_]+
apply function String.prototype.toUpperCase() only to the first character of each word.
function first_char_to_uppercase(argument) {
return argument.replace(/\w+/g, function(word) {
return word.charAt(0).toUpperCase() + word.slice(1);
});
}
Examples:
first_char_to_uppercase("I'm a little tea pot");
// "I'M A Little Tea Pot"
// This may look wrong to you, but was the intended result for me
// You may wanna extend the regex to get the result you desire, e.g., /[\w']+/
first_char_to_uppercase("maRy hAd a lIttLe LaMb");
// "MaRy HAd A LIttLe LaMb"
// Again, it does not convert words to Titlecase
first_char_to_uppercase(
"ExampleX: CamelCase/UPPERCASE&lowercase,exampleY:N0=apples"
);
// "ExampleX: CamelCase/UPPERCASE&Lowercase,ExampleY:N0=Apples"
first_char_to_uppercase("…n1=orangesFromSPAIN&&n2!='a sub-string inside'");
// "…N1=OrangesFromSPAIN&&N2!='A Sub-String Inside'"
first_char_to_uppercase("snake_case_example_.Train-case-example…");
// "Snake_case_example_.Train-Case-Example…"
// Note that underscore _ is part of the RegEx \w+
first_char_to_uppercase(
"Capitalize First Letter of each word in a String - JavaScript"
);
// "Capitalize First Letter Of Each Word In A String - JavaScript"
Edit 2019-02-07: If you want actual Titlecase (i.e. only the first letter uppercase all others lowercase):
function titlecase_all_words(argument) {
return argument.replace(/\w+/g, function(word) {
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
});
}
Examples showing both:
test_phrases = [
"I'm a little tea pot",
"maRy hAd a lIttLe LaMb",
"ExampleX: CamelCase/UPPERCASE&lowercase,exampleY:N0=apples",
"…n1=orangesFromSPAIN&&n2!='a sub-string inside'",
"snake_case_example_.Train-case-example…",
"Capitalize First Letter of each word in a String - JavaScript"
];
for (el in test_phrases) {
let phrase = test_phrases[el];
console.log(
phrase,
"<- input phrase\n",
first_char_to_uppercase(phrase),
"<- first_char_to_uppercase\n",
titlecase_all_words(phrase),
"<- titlecase_all_words\n "
);
}
// I'm a little tea pot <- input phrase
// I'M A Little Tea Pot <- first_char_to_uppercase
// I'M A Little Tea Pot <- titlecase_all_words
// maRy hAd a lIttLe LaMb <- input phrase
// MaRy HAd A LIttLe LaMb <- first_char_to_uppercase
// Mary Had A Little Lamb <- titlecase_all_words
// ExampleX: CamelCase/UPPERCASE&lowercase,exampleY:N0=apples <- input phrase
// ExampleX: CamelCase/UPPERCASE&Lowercase,ExampleY:N0=Apples <- first_char_to_uppercase
// Examplex: Camelcase/Uppercase&Lowercase,Exampley:N0=Apples <- titlecase_all_words
// …n1=orangesFromSPAIN&&n2!='a sub-string inside' <- input phrase
// …N1=OrangesFromSPAIN&&N2!='A Sub-String Inside' <- first_char_to_uppercase
// …N1=Orangesfromspain&&N2!='A Sub-String Inside' <- titlecase_all_words
// snake_case_example_.Train-case-example… <- input phrase
// Snake_case_example_.Train-Case-Example… <- first_char_to_uppercase
// Snake_case_example_.Train-Case-Example… <- titlecase_all_words
// Capitalize First Letter of each word in a String - JavaScript <- input phrase
// Capitalize First Letter Of Each Word In A String - JavaScript <- first_char_to_uppercase
// Capitalize First Letter Of Each Word In A String - Javascript <- titlecase_all_words
function titleCase(str) {
var myString = str.toLowerCase().split(' ');
for (var i = 0; i < myString.length; i++) {
var subString = myString[i].split('');
for (var j = 0; j < subString.length; j++) {
subString[0] = subString[0].toUpperCase();
}
myString[i] = subString.join('');
}
return myString.join(' ');
}
TypeScript fat arrow FTW
export const formatTitleCase = (string: string) =>
string
.toLowerCase()
.split(" ")
.map((word) => word.charAt(0).toUpperCase() + word.substring(1))
.join(" ");
Here's how you could do it with the map function basically, it does the same as the accepted answer but without the for-loop. Hence, saves you few lines of code.
function titleCase(text) {
if (!text) return text;
if (typeof text !== 'string') throw "invalid argument";
return text.toLowerCase().split(' ').map(value => {
return value.charAt(0).toUpperCase() + value.substring(1);
}).join(' ');
}
console.log(titleCase("I'm A little tea pot"));
A more compact (and modern) rewrite of #somethingthere's proposed solution:
let titleCase = (str => str.toLowerCase().split(' ').map(
c => c.charAt(0).toUpperCase() + c.substring(1)).join(' '));
document.write(titleCase("I'm an even smaller tea pot"));
Below is another way to capitalize the first alphabet of each word in a string.
Create a custom method for a String object by using prototype.
String.prototype.capitalize = function() {
var c = '';
var s = this.split(' ');
for (var i = 0; i < s.length; i++) {
c+= s[i].charAt(0).toUpperCase() + s[i].slice(1) + ' ';
}
return c;
}
var name = "john doe";
document.write(name.capitalize());
This is a perfect example of using modern javascript practices to improve readability. Have not yet seen a reduce version here, but this is what i use. Its both a curried one-liner and very readable
sentence
.trim().toLowerCase()
.split(' ')
.reduce((sentence, word) => `${sentence} ${word[0].toUpperCase()}${word.substring(1)}`, '')
.trim()
With Regex and handling special characters like ñ with multiple spaces in between : /(^.|\s+.)/g
let text = "ñora ñora"
console.log(text.toLowerCase().replace(/(^.|\s+.)/g, m => m.toUpperCase()))
Raw code:
function capi(str) {
var s2 = str.trim().toLowerCase().split(' ');
var s3 = [];
s2.forEach(function(elem, i) {
s3.push(elem.charAt(0).toUpperCase().concat(elem.substring(1)));
});
return s3.join(' ');
}
capi('JavaScript string exasd');
I used replace() with a regular expression:
function titleCase(str) {
var newStr = str.toLowerCase().replace(/./, (x) => x.toUpperCase()).replace(/[^']\b\w/g, (y) => y.toUpperCase());
console.log(newStr);
}
titleCase("I'm a little tea pot")
A complete and simple solution goes here:
String.prototype.replaceAt=function(index, replacement) {
return this.substr(0, index) + replacement+ this.substr(index
+ replacement.length);
}
var str = 'k j g u i l p';
function capitalizeAndRemoveMoreThanOneSpaceInAString() {
for(let i = 0; i < str.length-1; i++) {
if(str[i] === ' ' && str[i+1] !== '')
str = str.replaceAt(i+1, str[i+1].toUpperCase());
}
return str.replaceAt(0, str[0].toUpperCase()).replace(/\s+/g, ' ');
}
console.log(capitalizeAndRemoveMoreThanOneSpaceInAString(str));

camelCase to kebab-case

I have a kebabize function which converts camelCase to kebab-case. I am sharing my code. Can it be more optimized? I know this problem can be solved using regex. But, I want to do it without using regex.
const kebabize = str => {
let subs = []
let char = ''
let j = 0
for( let i = 0; i < str.length; i++ ) {
char = str[i]
if(str[i] === char.toUpperCase()) {
subs.push(str.slice(j, i))
j = i
}
if(i == str.length - 1) {
subs.push(str.slice(j, str.length))
}
}
return subs.map(el => (el.charAt(0).toLowerCase() + el.substr(1, el.length))).join('-')
}
kebabize('myNameIsStack')
const kebabize = str => {
return str.split('').map((letter, idx) => {
return letter.toUpperCase() === letter
? `${idx !== 0 ? '-' : ''}${letter.toLowerCase()}`
: letter;
}).join('');
}
console.log(kebabize('myNameIsStack'));
console.log(kebabize('MyNameIsStack'));
You can just check every letter is if upperCase or not and replace it.
I have a one-liner similar to Marc's but with a simpler Regular Expression and ~20% faster according my benchmark (Chrome 89).
const kebabize = (str) => str.replace(/[A-Z]+(?![a-z])|[A-Z]/g, ($, ofs) => (ofs ? "-" : "") + $.toLowerCase())
const words = ['StackOverflow', 'camelCase', 'alllowercase', 'ALLCAPITALLETTERS', 'CustomXMLParser', 'APIFinder', 'JSONResponseData', 'Person20Address', 'UserAPI20Endpoint'];
console.log(words.map(kebabize));
[A-Z]+(?![a-z]) matches any consecutive capital letters, excluding any capitals followed by a lowercase (signifying the next word). Adding |[A-Z] then includes any single capital letters. It must be after the consecutive capital expression, otherwise the expression will match all capital letters individually and never match consecutives.
String.prototype.replace can take a replacer function. Here, it returns the lowercased matched capital(s) for each word, after prefixing a hyphen when the match offset is truthy (not zero - not the first character of the string).
I suspect Marc's solution is less performant than mine because by using replace to insert hyphens and lowercasing the whole string afterwards, it must iterate over the string more than once, and its expression also has more complex look aheads/behind constructs.
Benchmark
RegEx is faster!
Unlike what you might think, the RegEx way of doing this is actually significantly faster! See benchmark.
The function below supports converting both camelCase and PascalCase into kebab-case:
function toKebabCase(str) {
return str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
}
Here is my solution:
Works with camelCase and PascalCase:
let words = ['StackOverflow', 'camelCase', 'alllowercase', 'ALLCAPITALLETTERS', 'CustomXMLParser', 'APIFinder', 'JSONResponseData', 'Person20Address', 'UserAPI20Endpoint'];
let result = words.map(w => w.replace(/((?<=[a-z\d])[A-Z]|(?<=[A-Z\d])[A-Z](?=[a-z]))/g, '-$1').toLowerCase());
console.log(result);
/*
Returns:
[
"stack-overflow",
"camel-case",
"alllowercase",
"allcapitalletters",
"custom-xml-parser",
"api-finder",
"json-response-data",
"person20-address",
"user-api20-endpoint"
]
*/
Explanation:
Match any of the following regular expressions:
Find any capital letter, that is immediately preceeded by a small letter or a number, or
Find any capital letter, that is immediately preceeded by a capital letter or a number, that is immediately followed by a small letter
Replace the captured position with a dash ('-') followed by the captured capital letter
Finally, convert the whole string to lowercase.
I would use something like this.
function kebabize(string) {
// uppercase after a non-uppercase or uppercase before non-uppercase
const upper = /(?<!\p{Uppercase_Letter})\p{Uppercase_Letter}|\p{Uppercase_Letter}(?!\p{Uppercase_Letter})/gu;
return string.replace(upper, "-$&").replace(/^-/, "").toLowerCase();
}
const strings = ["myNameIsStack", "HTTPRequestData", "DataX", "Foo6HelloWorld9Bar", "Áb"];
const result = strings.map(kebabize);
console.log(result);
This snippet replaces all uppercase characters before or after a non-uppercase character with - followed by the uppercase. It then removes the - at the start of the string (if there is any) and downcases the whole string.
Simple solution for older browsers:
var str = 'someExampleString'
var i
function camelToKebab() {
var __str = arguments[0]
var __result = ''
for (i = 0; i < __str.length; i++) {
var x = __str[i]
if(x === x.toUpperCase()) {
__result += '-' + x.toLowerCase()
} else {
__result += x
}
}
return __result
}
console.log(str, '->', camelToKebab(str))
Here is the solution I came up with:
let resultDiv = document.querySelector(".result");
let camelCase = "thisIsCamelCase";
let kebabCase;
kebabCase = camelCase.split('').map(el=> {
const charCode = el.charCodeAt(0);
if(charCode>=65 && charCode<=90){
return "-" + el.toLowerCase()
}else{
return el;
}
})
return(kebabCase.join(''))

How to replace a character with an specific indexOf to uppercase in a string?

Im trying to replace a character at a specific indexOf to uppercase.
My string is a surname plus the first letter in the last name,
looking like this: "lovisa t".
I check the position with this and it gives me the right place in the string. So the second gives me 8(in this case).
first = texten.indexOf(" ");
second = texten.indexOf(" ", first + 1);
And with this I replace the first letter to uppercase.
var name = texten.substring(0, second);
name=name.replace(/^./, name[0].toUpperCase());
But how do I replace the character at "second" to uppercase?
I tested with
name=name.replace(/.$/, name[second].toUpperCase());
But it did´t work, so any input really appreciated, thanks.
Your error is the second letter isn't in position 8, but 7.
Also this second = texten.indexOf(" ", first + 1); gives -1, not 8, because you do not have a two spaces in your string.
If you know that the string is always in the format surname space oneLetter and you want to capitalize the first letter and the last letter you can simply do this:
var name = 'something s';
name = name[0].toUpperCase() + name.substring(1, name.length - 1) + name[name.length -1].toUpperCase();
console.log(name)
Here's a version that does exactly what your question title asks for: It uppercases a specific index in a string.
function upperCaseAt(str, i) {
return str.substr(0, i) + str.charAt(i).toUpperCase() + str.substr(i + 1);
}
var str = 'lovisa t';
var i = str.indexOf(' ');
console.log(upperCaseAt(str, i + 1));
However, if you want to look for specific patterns in the string, you don't need to deal with indices.
var str = 'lovisa t';
console.log(str.replace(/.$/, function (m0) { return m0.toUpperCase(); }));
This version uses a regex to find the last character in a string and a replacement function to uppercase the match.
var str = 'lovisa t';
console.log(str.replace(/ [a-z]/, function (m0) { return m0.toUpperCase(); }));
This version is similar but instead of looking for the last character, it looks for a space followed by a lowercase letter.
var str = 'lovisa t';
console.log(str.replace(/(?:^|\s)\S/g, function (m0) { return m0.toUpperCase(); }));
Finally, here we're looking for (and uppercasing) all non-space characters that are preceded by the beginning of the string or a space character; i.e. we're uppercasing the start of each (space-separated) word.
All can be done by regex replace.
"lovisa t".replace(/(^|\s)\w/g, s=>s.toUpperCase());
Try this one (if it will be helpfull, better move constants to other place, due performance issues(yes, regexp creation is not fast)):
function normalize(str){
var LOW_DASH = /\_/g;
var NORMAL_TEXT_REGEXP = /([a-z])([A-Z])/g;
if(!str)str = '';
if(str.indexOf('_') > -1) {
str = str.replace(LOW_DASH, ' ');
}
if(str.match(NORMAL_TEXT_REGEXP)) {
str = str.replace(NORMAL_TEXT_REGEXP, '$1 $2');
}
if(str.indexOf(' ') > -1) {
var p = str.split(' ');
var out = '';
for (var i = 0; i < p.length; i++) {
if (!p[i])continue;
out += p[i].charAt(0).toUpperCase() + p[i].substring(1) + (i !== p.length - 1 ? ' ' : '');
}
return out;
} else {
return str.charAt(0).toUpperCase() + str.substring(1);
}
}
console.log(normalize('firstLast'));//First Last
console.log(normalize('first last'));//First Last
console.log(normalize('first_last'));//First Last

Replace nth word in sentence

I have a function that get string, I'm looking for a way to format the 3rd word (which is number, that i want to format it with comma). any idea how to do it?
should be something like that:
function formatNumber(txt){
return txt.replace(3rd-word, formatNumber(3rd-word));
}
Match any word that consists of digits, and format it:
txt = txt.replace(/\b(\d+)\b/g, format);
using a formatting function, for example:
function format(s) {
var r = '';
while (s.length > 3) {
r = ',' + s.substr(s.length - 3) + r;
s = s.substr(0, s.length - 3);
}
return s + r;
}
Demo: http://jsfiddle.net/Guffa/5yA62/
Break it down into parts.
Create a function that transforms your word into the format you want.
Split your sentence into words.
Run that function against the appropriate word.
Put the words back into a sentence.
This does not solve your problem. You would still need to find a way to format the number as you choose, but it solves a similar problem of uppercasing the third word:
var transformNth = function(n, fn) {
return function(arr) {
arr[n] = fn(arr[n]);
return arr;
}
};
var makeWords = function(sentence) {return sentence.split(" ");};
var upperCase = function(word) {return word.toUpperCase();}
var transformSentence = function(sentence) {
// index 2 is the third word
return transformNth(2, upperCase)(makeWords(sentence)).join(" ");
}
transformSentence("I have a function that get string");
//=> "I have A function that get string"
transformSentence("I'm looking for a way to format the 3rd word");
//=> "I'm looking FOR a way to format the 3rd word"
transformSentence("which is number");
//=> "which is NUMBER"
transformSentence("that i want to format it with comma");
//=> "that i WANT to format it with comma"
transformSentence("any idea how to do it?");
//=> "any idea HOW to do it?"
transformSentence("should be something like that");
//=> "should be SOMETHING like that"
It might have problems if your sentences have some more complicated structure than single whitespace separation of words that you want to maintain...
You can get the n-th word from the sentence by splitting it up and executing a replace on the word index as specified.
Here is a demo for the code below: DEMO
var sentence = "Total is 123456789!"
var formatNumber = function(value) {
return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
var replaceWord = function(sentence, pos, formatterFunction) {
var matches = sentence.match(/(\b[^\s]+\b)/g);
if (pos < 0 && pos >= matches.length) {
throw "Index out of bounds: " + pos;
}
var match = matches[pos];
var bounded = new RegExp('\\b' + match + '\\b');
return sentence.replace(bounded, formatterFunction(match));
};
console.log(replaceWord(sentence, 2, formatNumber)); // Total is 123,456,789!

JavaScript: replace last occurrence of text in a string

See my code snippet below:
var list = ['one', 'two', 'three', 'four'];
var str = 'one two, one three, one four, one';
for ( var i = 0; i < list.length; i++)
{
if (str.endsWith(list[i])
{
str = str.replace(list[i], 'finish')
}
}
I want to replace the last occurrence of the word one with the word finish in the string, what I have will not work because the replace method will only replace the first occurrence of it. Does anyone know how I can amend that snippet so that it only replaces the last instance of 'one'
Well, if the string really ends with the pattern, you could do this:
str = str.replace(new RegExp(list[i] + '$'), 'finish');
You can use String#lastIndexOf to find the last occurrence of the word, and then String#substring and concatenation to build the replacement string.
n = str.lastIndexOf(list[i]);
if (n >= 0 && n + list[i].length >= str.length) {
str = str.substring(0, n) + "finish";
}
...or along those lines.
Not as elegant as the regex answers above, but easier to follow for the not-as-savvy among us:
function removeLastInstance(badtext, str) {
var charpos = str.lastIndexOf(badtext);
if (charpos<0) return str;
ptone = str.substring(0,charpos);
pttwo = str.substring(charpos+(badtext.length));
return (ptone+pttwo);
}
I realize this is likely slower and more wasteful than the regex examples, but I think it might be helpful as an illustration of how string manipulations can be done. (It can also be condensed a bit, but again, I wanted each step to be clear.)
Here's a method that only uses splitting and joining. It's a little more readable so thought it was worth sharing:
String.prototype.replaceLast = function (what, replacement) {
var pcs = this.split(what);
var lastPc = pcs.pop();
return pcs.join(what) + replacement + lastPc;
};
Thought I'd answer here since this came up first in my Google search and there's no answer (outside of Matt's creative answer :)) that generically replaces the last occurrence of a string of characters when the text to replace might not be at the end of the string.
if (!String.prototype.replaceLast) {
String.prototype.replaceLast = function(find, replace) {
var index = this.lastIndexOf(find);
if (index >= 0) {
return this.substring(0, index) + replace + this.substring(index + find.length);
}
return this.toString();
};
}
var str = 'one two, one three, one four, one';
// outputs: one two, one three, one four, finish
console.log(str.replaceLast('one', 'finish'));
// outputs: one two, one three, one four; one
console.log(str.replaceLast(',', ';'));
A simple answer without any regex would be:
str = str.substr(0, str.lastIndexOf(list[i])) + 'finish'
I did not like any of the answers above and came up with the below
function isString(variable) {
return typeof (variable) === 'string';
}
function replaceLastOccurrenceInString(input, find, replaceWith) {
if (!isString(input) || !isString(find) || !isString(replaceWith)) {
// returns input on invalid arguments
return input;
}
const lastIndex = input.lastIndexOf(find);
if (lastIndex < 0) {
return input;
}
return input.substr(0, lastIndex) + replaceWith + input.substr(lastIndex + find.length);
}
Usage:
const input = 'ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty';
const find = 'teen';
const replaceWith = 'teenhundred';
const output = replaceLastOccurrenceInString(input, find, replaceWith);
console.log(output);
// output: ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteenhundred twenty
Hope that helps!
Couldn't you just reverse the string and replace only the first occurrence of the reversed search pattern? I'm thinking . . .
var list = ['one', 'two', 'three', 'four'];
var str = 'one two, one three, one four, one';
for ( var i = 0; i < list.length; i++)
{
if (str.endsWith(list[i])
{
var reversedHaystack = str.split('').reverse().join('');
var reversedNeedle = list[i].split('').reverse().join('');
reversedHaystack = reversedHaystack.replace(reversedNeedle, 'hsinif');
str = reversedHaystack.split('').reverse().join('');
}
}
If speed is important, use this:
/**
* Replace last occurrence of a string with another string
* x - the initial string
* y - string to replace
* z - string that will replace
*/
function replaceLast(x, y, z){
var a = x.split("");
var length = y.length;
if(x.lastIndexOf(y) != -1) {
for(var i = x.lastIndexOf(y); i < x.lastIndexOf(y) + length; i++) {
if(i == x.lastIndexOf(y)) {
a[i] = z;
}
else {
delete a[i];
}
}
}
return a.join("");
}
It's faster than using RegExp.
Simple solution would be to use substring method.
Since string is ending with list element, we can use string.length and calculate end index for substring without using lastIndexOf method
str = str.substring(0, str.length - list[i].length) + "finish"
function replaceLast(text, searchValue, replaceValue) {
const lastOccurrenceIndex = text.lastIndexOf(searchValue)
return `${
text.slice(0, lastOccurrenceIndex)
}${
replaceValue
}${
text.slice(lastOccurrenceIndex + searchValue.length)
}`
}
A negative lookahead solution:
str.replace(/(one)(?!.*\1)/, 'finish')
An explanation provided by the site regex101.com,
/(one)(?!.*\1)/
1st Capturing Group (one)
one - matches the characters one literally (case sensitive)
Negative Lookahead (?!.*\1)
Assert that the Regex below does not match
. matches any character (except for line terminators)
* matches the previous token between zero and unlimited times, as many times as possible, giving back as needed (greedy)
\1 matches the same text as most recently matched by the 1st capturing group
Old fashioned and big code but efficient as possible:
function replaceLast(origin,text){
textLenght = text.length;
originLen = origin.length
if(textLenght == 0)
return origin;
start = originLen-textLenght;
if(start < 0){
return origin;
}
if(start == 0){
return "";
}
for(i = start; i >= 0; i--){
k = 0;
while(origin[i+k] == text[k]){
k++
if(k == textLenght)
break;
}
if(k == textLenght)
break;
}
//not founded
if(k != textLenght)
return origin;
//founded and i starts on correct and i+k is the first char after
end = origin.substring(i+k,originLen);
if(i == 0)
return end;
else{
start = origin.substring(0,i)
return (start + end);
}
}
I would suggest using the replace-last npm package.
var str = 'one two, one three, one four, one';
var result = replaceLast(str, 'one', 'finish');
console.log(result);
<script src="https://unpkg.com/replace-last#latest/replaceLast.js"></script>
This works for string and regex replacements.
if (string.search(searchstring)>-1) {
stringnew=((text.split("").reverse().join("")).replace(searchstring,
subststring).split("").reverse().join(""))
}
//with var string= "sdgu()ert(dhfj ) he ) gfrt"
//var searchstring="f"
//var subststring="X"
//var stringnew=""
//results in
//string : sdgu()ert(dhfj ) he ) gfrt
//stringnew : sdgu()ert(dhfj ) he ) gXrt
str = (str + '?').replace(list[i] + '?', 'finish');

Categories