How to remove specific character surrounding a string? - javascript

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();

Related

How to swap first and last letter case in each word after using reverse() in JavaScript

I wanna try swapping cases for the first and last letters in each word that are already reversed using the reverse function.
Let's say I have a string like this.
I am Firdaus
And I wanna make it just like this.
I ma Suadrif
Here is how the script looks like
let reverseWords = str => {
console.log(`Input: ${str}`)
let words = str.split(" ").map(word => {
let chars = word.split("").reverse();
let result = chars.map((char, index) => {
if (index == chars.length-1 && chars.length != 0 && char == char.toUpperCase() && index != 0) {
return char.toLowerCase();
}
return char;
});
return result.join('');
});
return words.join(' ');
}
console.log(`Output: ${reverseWords("I am Firdaus")}`);
If you run the code above, the result is not like what I expected
The uppercase F successfully becomes lowercase f, but the lowercase s failed to become uppercase S. I am confused about how to swap the s become an uppercase S.
Is there a way and the best way to make the string just like what I expected?
Thanks in advance.
It look like you need to compare against the original string's casing to determine whether the returned character should be upper-cased or lower-cased. Use the index of the (reversed) character you're mapping over to access the original character at the same index in the original word.
const reverseWords = str => str
.split(' ')
.map(word => [...word].reverse()
.map((char, i) => (
word[i].toLowerCase() === word[i]
? char.toLowerCase()
: char.toUpperCase()
))
.join('')
)
.join(' ');
console.log(`Output: ${reverseWords("I am Firdaus")}`);

Counting brackets in a string

been working on a school problem, and haven't been able to figure it out. Any help is appreciated!
Write a function named countBrackets that accepts a string
and returns the count of square bracket and curly bracket
characters in the string. That is, it should count occurrences of
these four characters “{ } [ ]”. Use function expression syntax.
var countBrackets = function(s){
let sum = 0
for(let i = ""; i == s ; i++ )
if(i ==="{}[]"){
sum+=i
}
return sum}
console.log(countBrackets("[123],{456},[{}]")) //8
console.log(countBrackets("Test string")) // 0
I'm a little confused on how I'm supposed to get it to count a string I guess.
You can use a global regex (regular expression) matching for this. The regex is between / / followed by the g flag to make it global (otherwise it only returns the first result it finds and stops).
Within the regex, | is the OR operator, so you match for /{|}|[|]/
Since [ and ] have special meaning in regular expressions you need to escape those using a \ so your total regex becomes /{|}|\[|\]/g.
This returns an array of matches, I called the function findBrackets.
To get the number of brackets, the function countBrackets just returns the .length of that array.
const findBrackets = str => str.match(/{|}|\[|\]/g);
const countBrackets = str => findBrackets(str) ? findBrackets(str).length : 0;
console.log(findBrackets('qw[e}rt[y]ui{}o{p'));
console.log(countBrackets('qw[e}rt[y]ui{}o{p'));
console.log(countBrackets('no brackets here'));
Edit: seeing the code you posted, you decided to use a for-loop to loop over your string, which is a totally valid solution.
Note that in my above example
const findBrackets = str => str.match(/{|}|\[|\]/g);
Is basically the same but a newer way of writing functions (with a few nuances)
I could have written:
var findBrackets = function(str) {
return str.match(/{|}|\[|\]/g);
}
instead which would be almost the same.
If you want to loop over a string, you can access a letter in the string by using square bracket notation, so for example
const testString = 'hello';
console.log(testString[1]);
Would output the letter 'e'.
So to use this in a function:
const countBrackets = (str) => {
let counter = 0;
for (let i = 0; i < str.length; i++) {
if (str[i] === '[' || str[i] === ']' || str[i] === '{' || str[i] === '}') {
counter++;
}
}
return counter;
}
console.log(countBrackets('qw[e}rt[y]ui{}o{p'));
Here you loop over the string from 0 to < length of the string and check every letter of it, by seeing if str[i] is {, }, [ or ], and if it is you increment a counter. After that's done you return the final count.

Why non-space elements in string aren't changing to upperCase

I want to write a function to change the characters in a string at even indices to uppercase. I don't want my program to count the spaces as an even index, even if it falls on an even index.
For example: 'This is a test' => 'ThIs Is A TeSt'
I originally had this solution, but I could not get it to work to ignore the space characters when counting the even indices.
function toWeirdCase(string) {
return string.split("").map((x,i) => i%2=== 0 && x!== " " ? x.toUpperCase() : x).join("")
}
This is my second attempt and I don't know why the string elements aren't actually changing to uppercase. Any help on this would be appreciated. It is just returning the original string.
function toWeirdCase(string) {
let indexCount = 0;
let isSpace = false;
for (let i = 0; i < string.length; i++) {
if (string[i] === " ") {
isSpace = true;
}
if (indexCount % 2 === 0 && !isSpace) {
string[indexCount] = string[indexCount].toUpperCase();
}
indexCount++;
isSpace = false;
}
return string;
}
Answer:
You can use a modified reduce function that utilizes a closure as a character counter. This has the benefit of completing the transformation in one pass:
["", ...str].reduce((n =>
(r, c) => r += /\s/.test(c) ? c : c[`to${n++ & 1 ? "Lower" : "Upper"}Case`]())(0)
);
Example:
const biUpperCase = str => ["", ...str].reduce((n =>
(r, c) =>r += /\s/.test(c) ? c : c[`to${n++ & 1 ? "Lower" : "Upper"}Case`]())(0)
);
let test = biUpperCase("This is a Test");
console.log(test);
Explanation:
n is a character counter that keeps track of all non-space characters. You can think of this as an additional index that only worries about non-space characters.
We use this to determine whether or not a character is an even or odd non-space character by performing bitwise AND ( n & 1 ) or, alternatively, by performing a modulus operation ( n % 2 )
r is the accumulator in the Array.prototype.reduce method. This is what is returned by our reduce method.
Since there was no secondary parameter to Array.prototype.reduce, the first index of the Array is used as the accumulator.
This is why we perform ["", ...str] instead of simply [...str].
Syntactically we could also have written [...str].reduce( fn , "" ) instead of ["", ...str].reduce( fn ), but this would alter our succinct code.
c is the current character that we are looking at within the string array. We use RegExp.prototype.match to determine if it's a space character.
if it is we simply add the space to r ( our accumulated string )
if it is not we add a transformed character to r ( our accumulated string )
To determine which case transformation( upper or lower ) should be applied we check if n ( our character counter ) is even or odd.
if n++ & 1 is truthy the case is lower
if n++ & 1 is falsy the case is upper
Aside:
You'll notice in the snippet and code I provided that I changed your parameter name string to str. The reason for this is because String is a built-in Constructor in JavaScript and it's best to never purposefully "cross the streams" when naming variables.
In the current way that you're attempting to use this variable it makes no difference since it's properly scoped, and truthfully it is up to you if you want to take my advice. Just be aware that it could lead to an annoying, invisible problem.
Hope this Helps! Happy Coding!
You could rewind the index counter for a single word.
function toWeirdCase(string) {
return Array
.from(
string,
(i => x => (/[a-z]/i.test(x) ? i++ : (i = 0)) % 2 ? x : x.toUpperCase())
(0)
)
.join('');
}
console.log(toWeirdCase('This is a test')); // 'ThIs Is A TeSt'
A string in javascript is immutable so you will need to do something like :
let test = 'This is a test';
test = toWeirdCase(test); //Here you assign the result
And here is an example solution which ignores spaces in the count
function toWeirdCase(string) {
let count = 0;
return string.split("").map((x) => {
if(x !== " ")
count++;
if(count%2 === 0) return x.toUpperCase();
else return x;
}).join("")
}
let test = 'This is a test';
test = toWeirdCase(test);
console.log(test); //THiS iS a TeSt
Like the comments mention, strings in Javascript are immutable. That being said, you can break down the input string on whitespace, do the transformations, and join back into a string, something like this -
function toWeirdCase(sentence) {
return sentence
.split(' ')
.map(word => word
.split('')
.map((c, i) => i % 2 ? c : c.toUpperCase())
.join('')).join(' ');
}
You could store the number of spaces in a variable in the functions scope.
function toWeirdCase(string) {
let spaceCount = 0;
// Personal preference: I like the reduce fn for this, but a similar thing could be achieved with map
return string.split('').reduce((value, letter, index) => {
if (letter === ' ') spaceCount++;
return value += ((index - spaceCount) % 2)
? letter
: letter.toUpperCase();
},'')
}
This returns the leter if the index ingoring the space count has a remainder when divided by 2.
You can achieve this like so:
const str = "this is a test";
function toWeirdCase(str) {
return str.split(" ").map(word => (
[...word].map((c, i) => i % 2 ?
c.toLowerCase() :
c.toUpperCase())).join("")).join(" ");
}
console.log(toWeirdCase(str));
Updated: to set odd indexes toLowerCase() to handle edge cases like acronyms (ie: currency acronyms; "CA", "USD")
Hope this helps,

(replace) CamelCase function not work properly

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;
}

Delete first character of string if it is 0

I want to delete the first character of a string, if the first character is a 0. The 0 can be there more than once.
Is there a simple function that checks the first character and deletes it if it is 0?
Right now, I'm trying it with the JS slice() function but it is very awkward.
You can remove the first character of a string using substring:
var s1 = "foobar";
var s2 = s1.substring(1);
alert(s2); // shows "oobar"
To remove all 0's at the start of the string:
var s = "0000test";
while(s.charAt(0) === '0')
{
s = s.substring(1);
}
Very readable code is to use .substring() with a start set to index of the second character (1) (first character has index 0). Second parameter of the .substring() method is actually optional, so you don't even need to call .length()...
TL;DR : Remove first character from the string:
str = str.substring(1);
...yes it is that simple...
Removing some particular character(s):
As #Shaded suggested, just loop this while first character of your string is the "unwanted" character...
var yourString = "0000test";
var unwantedCharacter = "0";
//there is really no need for === check, since we use String's charAt()
while( yourString.charAt(0) == unwantedCharacter ) yourString = yourString.substring(1);
//yourString now contains "test"
.slice() vs .substring() vs .substr()
EDIT: substr() is not standardized and should not be used for new JS codes, you may be inclined to use it because of the naming similarity with other languages, e.g. PHP, but even in PHP you should probably use mb_substr() to be safe in modern world :)
Quote from (and more on that in) What is the difference between String.slice and String.substring?
He also points out that if the parameters to slice are negative, they
reference the string from the end. Substring and substr doesn´t.
Use .charAt() and .slice().
Example: http://jsfiddle.net/kCpNQ/
var myString = "0String";
if( myString.charAt( 0 ) === '0' )
myString = myString.slice( 1 );
If there could be several 0 characters at the beginning, you can change the if() to a while().
Example: http://jsfiddle.net/kCpNQ/1/
var myString = "0000String";
while( myString.charAt( 0 ) === '0' )
myString = myString.slice( 1 );
The easiest way to strip all leading 0s is:
var s = "00test";
s = s.replace(/^0+/, "");
If just stripping a single leading 0 character, as the question implies, you could use
s = s.replace(/^0/, "");
You can do it with substring method:
let a = "My test string";
a = a.substring(1);
console.log(a); // y test string
Did you try the substring function?
string = string.indexOf(0) == '0' ? string.substring(1) : string;
Here's a reference - https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/substring
And you can always do this for multiple 0s:
while(string.indexOf(0) == '0')
{
string = string.substring(1);
}
One simple solution is to use the Javascript slice() method, and pass 1 as a parameter
let str = "khattak01"
let resStr = str.slice(1)
console.log(resStr)
Result : hattak01
var s = "0test";
if(s.substr(0,1) == "0") {
s = s.substr(1);
}
For all 0s: http://jsfiddle.net/An4MY/
String.prototype.ltrim0 = function() {
return this.replace(/^[0]+/,"");
}
var s = "0000test".ltrim0();
const string = '0My string';
const result = string.substring(1);
console.log(result);
You can use the substring() javascript function.
//---- remove first and last char of str
str = str.substring(1,((keyw.length)-1));
//---- remove only first char
str = str.substring(1,(keyw.length));
//---- remove only last char
str = str.substring(0,(keyw.length));
try
s.replace(/^0/,'')
console.log("0string =>", "0string".replace(/^0/,'') );
console.log("00string =>", "00string".replace(/^0/,'') );
console.log("string00 =>", "string00".replace(/^0/,'') );
Here's one that doesn't assume the input is a string, uses substring, and comes with a couple of unit tests:
var cutOutZero = function(value) {
if (value.length && value.length > 0 && value[0] === '0') {
return value.substring(1);
}
return value;
};
http://jsfiddle.net/TRU66/1/
String.prototype.trimStartWhile = function(predicate) {
if (typeof predicate !== "function") {
return this;
}
let len = this.length;
if (len === 0) {
return this;
}
let s = this, i = 0;
while (i < len && predicate(s[i])) {
i++;
}
return s.substr(i)
}
let str = "0000000000ABC",
r = str.trimStartWhile(c => c === '0');
console.log(r);
Another alternative to get the first character after deleting it:
// Example string
let string = 'Example';
// Getting the first character and updtated string
[character, string] = [string[0], string.substr(1)];
console.log(character);
// 'E'
console.log(string);
// 'xample'
From the Javascript implementation of trim() > that removes and leading or ending spaces from strings. Here is an altered implementation of the answer for this question.
var str = "0000one two three0000"; //TEST
str = str.replace(/^\s+|\s+$/g,'0'); //ANSWER
Original implementation for this on JS
string.trim():
if (!String.prototype.trim) {
String.prototype.trim = function() {
return this.replace(/^\s+|\s+$/g,'');
}
}
Another alternative answer
str.replace(/^0+/, '')
var test = '0test';
test = test.replace(/0(.*)/, '$1');

Categories