(replace) CamelCase function not work properly - javascript

working with this function call:
var StringData = window.ToCamelCase({ 'string': 'HELLO WORLD', 'remSpace': false });
console.log(StringData);
and this is my script function:
function ToCamelCase(data) {
data['string'] = data['string'].replace(/(?:^\w|[A-Z]|\b\w)/g, function(word, index) {
return index == 0 ? word.toUpperCase() : word.toLowerCase();
});
if (data['remSpace']) {
data['string'] = data['string'].replace(/\s/g, '');
}
return data['string'];
}
i dont get error; but not work properly, if i passed and string like this:
"HELLO WORLD"
this moment second word not put first letter uppercase
the output is: "Hello world" and i expect: "Hello World"
First letter per word Upper Case and the following Lower Case is the rule.
what am I doing wrong?

You don't really need to use regex for this. You can split the string by using string.split(), then uppercase each element in the split array. Finally, recombine the array with spaces separating the elements if you want:
function ToCamelCase(data) {
const words = data['string'].toLowerCase().split(' ');
const uppercasedWords = words.map(word => {
let splitWord = word.split('');
splitWord[0] = splitWord[0].toUpperCase();
return splitWord.join('');
});
return uppercasedWords.join(data['remSpace'] ? '' : ' ')
}
or more functionally,
function uppercaseFirstElement(textArray) {
return [textArray[0].toUpperCase(), ...textArray.slice(1)];
}
function capitalizeWord(word) {
return uppercaseFirstElement(word.split('')).join('');
}
function toCamelCase(sentence, removeSpace) { // Really it should be `toPascalCase`
return sentence.toLowerCase().split(' ')
.map(capitalizeWord).join(removeSpace ? '' : ' ');
}

As mentioned by Ian, you do not need regular expressions for this job and it is probably more efficient to not use them.
That being said, if you DO want to make it work with a RegExp for whatever reason, you can use:
function toPascalCase(str) {
return str.replace(/(?:^|\s*)(\S+)(?:\s*|$)/g, (match, word) => word[0].toUpperCase() + word.slice(1).toLowerCase());
}
This code uses an es6 arrow function so you will need to change it if you want to be compatible with old browsers. This is also based on the spec I could get from your question but there are a lot of case non-handled regarding special characters outside of letters / numbers / whitespace range (they will be considered part of the words - it might be what you want though).
One last note: What you are trying to achieve is actually called PascalCase. In camelCase, the very first letter is lowercase.

First of all Ian's solution should be the correct one, since it is the simplest and understandable solution of them all.
If you are asking what's wrong with your code then my answer is this statement:
index == 0 ? word.toUpperCase() : word.toLowerCase()
is this statement what's causing all the problem. Your index is not 0 when it reaches to "W" of "World" so its going to make it lowercase.
Instead what you should be doing is capturing words and replace only the first letter of each word with an uppercase. Split method is a good solution, that's what Ian did. I have done something like this using the regex and replace, although its not necessary to do it like this.
function ToCamelCase(data) {
data['string'] = data['string'].replace(/(?:\s|^)(\w+)(?=\s|$)/g, function(word, index) {
var lowerWord = word.toLowerCase().trim();
return lowerWord.substring(0, 1).toUpperCase() + lowerWord.substring(1, word.length) + " "
});
if (data['remSpace']) {
data['string'] = data['string'].replace(/\s/g, '');
}
return data['string'];
}

In your code index will return always 0 as it is not iterating all your string characters
here I have tried with my code just replace with your code and let me know the result.
var StringData = window.toCamelCase({ 'string': 'HELLO WORLD', 'remSpace': false });
console.log(StringData);
function toCamelCase(data) {
var str = data['string'];
var isRemoveSpc = data['remSpace'];
var len = data['string'].length;
var newStr = "";
for(var i = 0; i < len; i++){
if( i == 0) {
newStr += str.charAt(i).toUpperCase();
} else if(str.charAt(i) == " ") {
if(isRemoveSpc) {
i++;
newStr += str.charAt(i).toUpperCase();
} else {
newStr += str.charAt(i);
i++;
newStr += str.charAt(i).toUpperCase();
}
} else {
newStr += str.charAt(i).toLowerCase();
}
}
return newStr;
}

Related

Add spaces before Capital Letters then turn them to lowercase string

I'm trying to make a function that caps space in which it takes input like "iLikeSwimming" then it outputs "i like swimming".
This is my try:
function isUpper(str) {
return !/[a-z]/.test(str) && /[A-Z]/.test(str);
}
function capSpace(txt) {
var arr = Array.from(txt);
for (let i = 1; i < txt.length; i++){
if (isUpper(txt[i]) == true) {
arr.splice((i),0,' ')
}
}
return arr.join('').toString().toLowerCase();
}
It's good for strings with only one capital letter, however, it gets kind of weird with more than one.
Example Input and outputs:
Inputs:
capSpace("iLikeSwimming"); capSpace("helloWorld");
Outputs:
'i lik eswimming' 'hello world'
I'd really appreciate it if someone can point the issue with my code. I know there are other questions "similar" to this, but I'm trying to learn my mistake rather than just copying, I couldn't make sense of any of the other questions. Thank you!
The reason why it gets weird with strings that have more than 1 capital letter is that every time you find one, you add a blank space which makes the following indices increase in a single unit.
It's a simple workaround: just place a counter splitCount to keep track of how many spaces you've added and sum it with the index i to correct the indices.
function isUpper(str) {
return !/[a-z]/.test(str) && /[A-Z]/.test(str);
}
function capSpace(txt) {
var arr = Array.from(txt);
var splitCount = 0; // added a counter
for (let i = 1; i < txt.length; i++){
if (isUpper(txt[i]) === true) {
// sum it with i
arr.splice((i + splitCount),0,' ')
splitCount++; // increase every time you split
}
}
return arr.join('').toString().toLowerCase();
}
console.log(capSpace('iLikeSwimming'))
1) You can simply achieve this using regex and string replace method
const capSpace = (str) => str.replace(/([A-Z])/g, (match) => ` ${match.toLowerCase()}`);
console.log(capSpace("iLikeSwimming"));
console.log(capSpace("helloWorld"));
2) You can also do with split, map and join
const capSpace = (str) =>
str
.split("")
.map((s) => (/[A-Z]/.test(s) ? ` ${s.toLowerCase()}` : s))
.join("");
console.log(capSpace("iLikeSwimming"));
console.log(capSpace("helloWorld"));
Here's a simple one I made. Matches capital letters then replaces them.
const testString = "ILoveMoney";
function caps2Spaces(str) {
const matches = str.match(/[A-Z]/g);
for (const letter of matches) {
str = str.replace(letter, ` ${letter.toLowerCase()}`)
}
return str.trim();
}
console.log(caps2Spaces(testString));

Algorithm - Search and Replace a string

I am doing a algorithm in freeCodeCamp.(https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/search-and-replace)
The task is as below:
Perform a search and replace on the sentence using the arguments provided and return the new sentence.
First argument is the sentence to perform the search and replace on.
Second argument is the word that you will be replacing (before).
Third argument is what you will be replacing the second argument with (after).
Note:
Preserve the case of the first character in the original word when you are replacing it. For example if you mean to replace the word "Book" with the word "dog", it should be replaced as "Dog"
**
myReplace("Let us get back to more Coding", "Coding", "algorithms") should return "Let us get back to more Algorithms".
myReplace("Let us go to the store", "store", "mall") should return "Let us go to the mall".
**
//if the before is uppercase, the after should be uppercase also
// str = str.replace(before, after);
var regex = /[A-Z]+/g; //check for uppercase
var newStr = "";
console.log(regex.test(before));
if (regex.test(before)) {
//if uppercase, return true, "after" convert to uppercase
after = after.toUpperCase();
newStr = after[0];
for (var i = 1; i < after.length; i++) {
//start at index=1 letter, all convert to
newStr += after[i].toLowerCase();
}
console.log(newStr);
str = str.replace(before, newStr);
} else {
str = str.replace(before, after);
}
// console.log(newStr);
console.log(str);
return str;
}
I think there should be OK for the code, but can anyone help find why the if statement can't work.
Much thanks!
The problem is that you're calling regex.test() multiple times on the same regular expression instance.
[...]
var regex = /[A-Z]+/g; //check for uppercase
var newStr = "";
console.log(regex.test(before));
if (regex.test(before)) {
//if uppercase, return true, "after" convert to uppercase
after = after.toUpperCase();
[...]
If your string is Hello_there, the first regex.test() will return true, because Hello matched. If you call regex.test() again with the same regex instance, it will have advanced in the string, and try to match starting with _there. In this case, it will fail, because _there does not begin with a capital letter between A and Z.
There are a lot of ways to fix this issue. Perhaps the simplest is to store the result of the first call to a variable, and use it everywhere you're calling regex.test():
[...]
var regex = /[A-Z]+/g; //check for uppercase
var newStr = "";
var upper_check = regex.test(before);
console.log(upper_check);
if (upper_check) {
[...]
It seems overkill to use a regex, when you really need to only check the first character. Your regex will find uppercase letters anywhere...
If the assignment is to only change one occurrence, then a regex is not really the right tool here: it does not really help to improve the code nor the efficiency. Just do:
function myReplace(str, before, after) {
if (before[0] === before[0].toUpperCase()) {
after = after[0].toUpperCase() + after.slice(1);
} else {
after = after[0].toLowerCase() + after.slice(1);
}
return str.replace(before, after);
}
function myReplace(str, before, after) {
var upperRegExp = /[A-Z]/g
var lowerRegExp = /[a-z]/g
var afterCapitalCase = after.replace(/^./, after[0].toUpperCase());
if (before[0].match(upperRegExp)) {
return str.replace(before, afterCapitalCase)
} else if (after[0].match(upperRegExp) && before[0].match(lowerRegExp)) {
return str.replace(before, after.toLowerCase());
} else {
return str.replace(before, after)
}
}

Return Alphanumerics -issue with combining pieces of the function

Submitted earlier about this, at this point all the pieces work separately, but not together. I've tried moving things around to see if it was simply an order issue, but that didn't fixe it. Trying to put them in one big if/else also didn't seem to work. I can either get the string to display only alphanumerics characters OR display 'not a string', but I cannot get the code to work to do both.
This section will return the proper alphanumerics only:
function nothingSpecial(str) {
var re = /[A-Z\s0-9]/i;
var newStr = '';
for(var i=0; i<str.length; i++){
if (re.test(str[i])){
newStr = newStr + str[i];
}
}
return newStr;
if(str.length <= 0) {
return ("Not a string!");
}
if (typeof str !== String) {
return "Not a string!"}
}
nothingSpecial("asdfalsd##$#")
This will return "not a string!", even if it should show alphanumerics, but is correct or seemingly so for numbers and ""
function nothingSpecial(str) {
var re = /[A-Z\s0-9]/i;
var newStr = '';
if(str.length <= 0) {
return ("Not a string!");
}
if (typeof str !== String) {
return "Not a string!"}
for(var i=0; i<str.length; i++){
if (re.test(str[i])){
newStr = newStr + str[i];
}
}
return newStr;
}
nothingSpecial(23)
What am I doing wrong? -Thank you in advance!
Edit: Okay, based on your comment, here you go:
This is your problem:
if (typeof str !== String)
You're comparing the result of typeof str, which is a string, with the object constructor for strings, String, which is a function. It's failing because you're not actually checking for a string, you're comparing a string (the output of typeof, which is always a string regardless of the type you're checking) with a function. Your comparison should instead look like this:
if (typeof str !== 'string')
Edit: Heres a JSFiddle.
To take any kind of argument, converting to string and keep just alphanumeric characters:
function nothingSpecial(str) {
str += '' // convert any argument to string
str = str.replace(/[^A-Z\s0-9]/gi, "") // remove all characters except alphanumeric and any kind of space (newlines too)
return str
}

How to remove specific character surrounding a string?

I have this string:
var str = "? this is a ? test ?";
Now I want to get this:
var newstr = "this is a ? test";
As you see I want to remove just those ? surrounding (in the beginning and end) that string (not in the middle of string). How can do that using JavaScript?
Here is what I have tried:
var str = "? this is a ? test ?";
var result = str.trim("?");
document.write(result);
So, as you see it doesn't work. Actually I'm a PHP developer and trim() works well in PHP. Now I want to know if I can use trim() to do that in JS.
It should be noted I can do that using regex, but to be honest I hate regex for this kind of jobs. Anyway is there any better solution?
Edit: As this mentioned in the comment, I need to remove both ? and whitespaces which are around the string.
Search for character mask and return the rest without.
This proposal the use of the bitwise not ~ operator for checking.
~ is a bitwise not operator. It is perfect for use with indexOf(), because indexOf returns if found the index 0 ... n and if not -1:
value ~value boolean
-1 => 0 => false
0 => -1 => true
1 => -2 => true
2 => -3 => true
and so on
function trim(s, mask) {
while (~mask.indexOf(s[0])) {
s = s.slice(1);
}
while (~mask.indexOf(s[s.length - 1])) {
s = s.slice(0, -1);
}
return s;
}
console.log(trim('??? this is a ? test ?', '? '));
console.log(trim('abc this is a ? test abc', 'cba '));
Simply use:
let text = '?? something ? really ??'
text = text.replace(/^([?]*)/g, '')
text = text.replace(/([?]*)$/g, '')
console.log(text)
A possible solution would be to use recursive functions to remove the unwanted leading and trailing characters. This doesn't use regular expressions.
function ltrim(char, str) {
if (str.slice(0, char.length) === char) {
return ltrim(char, str.slice(char.length));
} else {
return str;
}
}
function rtrim(char, str) {
if (str.slice(str.length - char.length) === char) {
return rtrim(char, str.slice(0, 0 - char.length));
} else {
return str;
}
}
Of course this is only one of many possible solutions. The function trim would use both ltrim and rtrim.
The reason that char is the first argument and the string that needs to be cleaned the second, is to make it easier to change this into a functional programming style function, like so (ES 2015):
function ltrim(char) {
(str) => {
<body of function>
}
}
// No need to specify str here
function ltrimSpaces = ltrim(' ');
Here is one way to do it which checks for index-out-of-bounds and makes only a single call to substring:
String.prototype.trimChars = function(chars) {
var l = 0;
var r = this.length-1;
while(chars.indexOf(this[l]) >= 0 && l < r) l++;
while(chars.indexOf(this[r]) >= 0 && r >= l) r--;
return this.substring(l, r+1);
};
Example:
var str = "? this is a ? test ?";
str.trimChars(" ?"); // "this is a ? test"
No regex:
uberTrim = s => s.length >= 2 && (s[0] === s[s.length - 1])?
s.slice(1, -1).trim()
: s;
Step-by-step explanation:
Check if the string is at least 2 characters long and if it is surrounded by a specific character;
If it is, then first slice it to remove the surrounding characters then trim it to remove whitespaces;
If not just return it.
In case you're weirded out by that syntax, it's an Arrow Function and a ternary operator.
The parenthesis are superfluous in the ternary by the way.
Example use:
uberTrim(''); // ''
uberTrim(' Plop! '); //'Plop!'
uberTrim('! ...What is Plop?!'); //'...What is Plop?'
Simple approach using Array.indexOf, Array.lastIndexOf and Array.slice functions:
Update: (note: the author has requested to trim the surrounding chars)
function trimChars(str, char){
var str = str.trim();
var checkCharCount = function(side) {
var inner_str = (side == "left")? str : str.split("").reverse().join(""),
count = 0;
for (var i = 0, len = inner_str.length; i < len; i++) {
if (inner_str[i] !== char) {
break;
}
count++;
}
return (side == "left")? count : (-count - 1);
};
if (typeof char === "string"
&& str.indexOf(char) === 0
&& str.lastIndexOf(char, -1) === 0) {
str = str.slice(checkCharCount("left"), checkCharCount("right")).trim();
}
return str;
}
var str = "???? this is a ? test ??????";
console.log(trimChars(str, "?")); // "this is a ? test"
to keep this question up to date using an ES6 approach:
I liked the bitwise method but when readability is a concern too then here's another approach.
function trimByChar(string, character) {
const first = [...string].findIndex(char => char !== character);
const last = [...string].reverse().findIndex(char => char !== character);
return string.substring(first, string.length - last);
}
Using regex
'? this is a ? test ?'.replace(/^[? ]*(.*?)[? ]*$/g, '$1')
You may hate regex but after finding a solution you will feel cool :)
Javascript's trim method only remove whitespaces, and takes no parameters. For a custom trim, you will have to make your own function. Regex would make a quick solution for it, and you can find an implementation of a custom trim on w3schools in case you don't want the trouble of going through the regex creation process. (you'd just have to adjust it to filter ? instead of whitespace
This in one line of code which returns your desire output:
"? this is a ? test ?".slice(1).slice(0,-1).trim();

How to capitalize the last letter of each word in a string

I am still rather new to JavaScript and I am having an issue of getting the first character of the string inside the array to become uppercase.
I have gotten to a point where I have gotten all the texted lowercase, reversed the text character by character, and made it into a string. I need to get the first letter in the string to uppercase now.
function yay () {
var input = "Party like its 2015";
return input.toLowerCase().split("").reverse().join("").split(" ");
for(var i = 1 ; i < input.length ; i++){
input[i] = input[i].charAt(0).toUpperCase() + input[i].substr(1);
}
}
console.log(yay());
I need the output to be "partY likE itS 2015"
Frustrating that you posted your initial question without disclosing the desired result. Lots of turmoil because of that. Now, that the desired result is finally clear - here's an answer.
You can lowercase the whole thing, then split into words, rebuild each word in the array by uppercasing the last character in the word, then rejoin the array:
function endCaseWords(input) {
return input.toLowerCase().split(" ").map(function(item) {
return item.slice(0, -1) + item.slice(-1).toUpperCase();
}).join(" ");
}
document.write(endCaseWords("Party like its 2015"));
Here's a step by step explanation:
Lowercase the whole string
Use .split(" ") to split into an array of words
Use .map() to iterate the array
For each word, create a new word that is the first part of the word added to an uppercased version of the last character in the word
.join(" ") back together into a single string
Return the result
You could also use a regex replace with a custom callback:
function endCaseWords(input) {
return input.toLowerCase().replace(/.\b/g, function(match) {
return match.toUpperCase();
});
}
document.write(endCaseWords("Party like its 2015"));
FYI, there are lots of things wrong with your original code. The biggest mistake is that as soon as you return in a function, no other code in that function is executed so your for loop was never executed.
Then, there's really no reason to need to reverse() the characters because once you split into words, you can just access the last character in each word.
Instead of returning the result splitting and reversing the string, you need to assign it to input. Otherwise, you return from the function before doing the loop that capitalizes the words.
Then after the for loop you should return the joined string.
Also, since you've reverse the string before you capitalize, you should be capitalizing the last letter of each word. Then you need to reverse the array before re-joining it, to get the words back in the original order.
function yay () {
var input = "Party like its 2015";
input = input.toLowerCase().split("").reverse().join("").split(" ");
for(var i = 1 ; i < input.length ; i++){
var len = input[i].length-1;
input[i] = input[i].substring(0, len) + input[i].substr(len).toUpperCase();
}
return input.reverse().join(" ");
}
alert(yay());
You can use regular expression for that:
input.toLowerCase().replace(/[a-z]\b/g, function (c) { return c.toUpperCase() });
Or, if you can use arrow functions, simply:
input.toLowerCase().replace(/[a-z]\b/g, c => c.toUpperCase())
Here's what I would do:
Split the sentence on the space character
Transform the resulting array using .map to capitalize the first character and lowercase the remaining ones
Join the array on a space again to get a string
function yay () {
var input = "Party like its 2015";
return input.split(" ").map(function(item) {
return item.charAt(0).toUpperCase() + item.slice(1).toLowerCase();
}).join(" ");
}
console.log(yay());
Some ugly, but working code:
var text = "Party like its 2015";
//partY likE itS 2015
function yay(input) {
input = input.split(' ');
arr = [];
for (i = 0; i < input.length; i++) {
new_inp = input[i].charAt(0).toLowerCase() + input[i].substring(1, input[i].length - 1) + input[i].charAt(input[i].length - 1).toUpperCase();
arr.push(new_inp);
}
str = arr.join(' ');
return str;
}
console.log(yay(text));
Try using ucwords from PHP.js. It's quite simple, actually.
String.prototype.ucwords = function() {
return (this + '')
.replace(/^([a-z\u00E0-\u00FC])|\s+([a-z\u00E0-\u00FC])/g, function($1) {
return $1.toUpperCase();
});
}
var input = "Party like its 2015";
input = input.charAt(0).toLowerCase() + input.substr(1);
input = input.split('').reverse().join('').ucwords();
input = input.split('').reverse().join('');
Note: I modified their function to be a String function so method chaining would work.
function yay(str)
{
let arr = str.split(' ');
let farr = arr.map((item) =>{
let x = item.split('');
let len = x.length-1
x[len] = x[len].toUpperCase();
x= x.join('')
return x;
})
return farr.join(' ')
}
var str = "Party like its 2015";
let output = yay(str);
console.log(output) /// "PartY likE itS 2015"
You can split and then map over the array perform uppercase logic and retun by joining string.
let string = "Party like its 2015";
const yay = (string) => {
let lastCharUpperCase = string.split(" ").map((elem) => {
elem = elem.toLowerCase();
return elem.replace(elem[elem.length - 1], elem[elem.length - 1].toUpperCase())
})
return lastCharUpperCase.join(" ");
}
console.log(yay(string))

Categories