How to replace all same charter/string in text with different outcomes? - javascript

For example let's say I want to attach the index number of each 's' in a string to the 's's.
var str = "This is a simple string to test regex.";
var rm = str.match(/s/g);
for (let i = 0;i < rm.length ;i++) {
str = str.replace(rm[i],rm[i]+i);
}
console.log(str);
Output: This43210 is a simple string to test regex.
Expected output: This0 is1 a s2imple s3tring to tes4t regex.

I'd suggest, using replace():
let i = 0,
str = "This is a simple string to test regex.",
// result holds the resulting string after modification
// by String.prototype.replace(); here we use the
// anonymous callback function, with Arrow function
// syntax, and return the match (the 's' character)
// along with the index of that found character:
result = str.replace(/s/g, (match) => {
return match + i++;
});
console.log(result);
Corrected the code with the suggestion — in comments — from Ezra.
References:
Arrow functions.
"Regular expressions," from MDN.
String.prototype.replace().

For something like this, I would personally go with the split and test method. For example:
var str = "This is a simple string to test regex.";
var split = str.split(""); //Split out every char
var recombinedStr = "";
var count = 0;
for(let i = 0; i < split.length; i++) {
if(split[i] == "s") {
recombinedStr += split[i] + count;
count++;
} else {
recombinedStr += split[i];
}
}
console.log(recombinedStr);
A bit clunky, but works. It forgoes using regex statements though, so probably not exactly what you're looking for.

Related

Palindrome Checker need a hand

I'm working on freeCodeCamp's Palindrome Checker. My code is a bit messy but it pretty works on every test except the nineth one. palindrome("almostomla") should return false but in my code it returns trueinstead. I think my nineth code has a little problem but couldn't solve that. I wonder where am I missing something.
function palindrome(str) {
let str1 = str.replace(/[^a-zA-Z\d:]/gi, '');
let str2 = str1.replace(/,/gi, '');
let str3 = str2.replace(/\./gi, '');
let str4 = str3.replace(/_/, "-");
let myStr = str4.toLowerCase(); //My string is ready for play
for (let i = 0; i < myStr.length; i++) {
if (myStr[i] != myStr[myStr.length - (i+1)]) { //I think there is a little mistake on this line
return false;
} else {
return true;
}
}
The problem is that you're only checking the first and last characters of the string. You should return true only after all iterations have finished:
function palindrome(str) {
let str1 = str.replace(/[^a-zA-Z\d:]/gi, '');
let str2 = str1.replace(/,/gi, '');
let str3 = str2.replace(/\./gi, '');
let str4 = str3.replace(/_/, "-");
let myStr = str4.toLowerCase(); //My string is ready for play
for (let i = 0; i < myStr.length; i++) {
if (myStr[i] != myStr[myStr.length - (i + 1)]) {
return false;
}
}
return true;
}
console.log(palindrome("almostomla"));
console.log(palindrome("foof"));
console.log(palindrome("fobof"));
console.log(palindrome("fobbf"));
Note that your initial regular expression is sufficient - it removes all characters that aren't alphabetical, numeric, or :, so the other 3 regular expressions you run later are superfluous. Since you're using the i flag, you can also remove the A-Z from the regex:
const stringToTest = str.replace(/[^a-z\d:]/gi, '');
It would also probably be easier just to .reverse() the string:
function palindrome(str) {
const strToTest = str.replace(/[^a-z\d:]/gi, '');
return strToTest.split('').reverse().join('') === strToTest;
}
console.log(palindrome("almostomla"));
console.log(palindrome("foof"));
console.log(palindrome("fobof"));
console.log(palindrome("fobbf"));

How to get odd and even position characters from a string?

I'm trying to figure out how to remove every second character (starting from the first one) from a string in Javascript.
For example, the string "This is a test!" should become "hsi etTi sats!"
I also want to save every deleted character into another array.
I have tried using replace method and splice method, but wasn't able to get them to work properly. Mostly because replace only replaces the first character.
function encrypt(text, n) {
if (text === "NULL") return n;
if (n <= 0) return text;
var encArr = [];
var newString = text.split("");
var j = 0;
for (var i = 0; i < text.length; i += 2) {
encArr[j++] = text[i];
newString.splice(i, 1); // this line doesn't work properly
}
}
You could reduce the characters of the string and group them to separate arrays using the % operator. Use destructuring to get the 2D array returned to separate variables
let str = "This is a test!";
const [even, odd] = [...str].reduce((r,char,i) => (r[i%2].push(char), r), [[],[]])
console.log(odd.join(''))
console.log(even.join(''))
Using a for loop:
let str = "This is a test!",
odd = [],
even = [];
for (var i = 0; i < str.length; i++) {
i % 2 === 0
? even.push(str[i])
: odd.push(str[i])
}
console.log(odd.join(''))
console.log(even.join(''))
It would probably be easier to use a regular expression and .replace: capture two characters in separate capturing groups, add the first character to a string, and replace with the second character. Then, you'll have first half of the output you need in one string, and the second in another: just concatenate them together and return:
function encrypt(text) {
let removedText = '';
const replacedText1 = text.replace(/(.)(.)?/g, (_, firstChar, secondChar) => {
// in case the match was at the end of the string,
// and the string has an odd number of characters:
if (!secondChar) secondChar = '';
// remove the firstChar from the string, while adding it to removedText:
removedText += firstChar;
return secondChar;
});
return replacedText1 + removedText;
}
console.log(encrypt('This is a test!'));
Pretty simple with .reduce() to create the two arrays you seem to want.
function encrypt(text) {
return text.split("")
.reduce(({odd, even}, c, i) =>
i % 2 ? {odd: [...odd, c], even} : {odd, even: [...even, c]}
, {odd: [], even: []})
}
console.log(encrypt("This is a test!"));
They can be converted to strings by using .join("") if you desire.
I think you were on the right track. What you missed is replace is using either a string or RegExp.
The replace() method returns a new string with some or all matches of a pattern replaced by a replacement. The pattern can be a string or a RegExp, and the replacement can be a string or a function to be called for each match. If pattern is a string, only the first occurrence will be replaced.
Source: String.prototype.replace()
If you are replacing a value (and not a regular expression), only the first instance of the value will be replaced. To replace all occurrences of a specified value, use the global (g) modifier
Source: JavaScript String replace() Method
So my suggestion would be to continue still with replace and pass the right RegExp to the function, I guess you can figure out from this example - this removes every second occurrence for char 't':
let count = 0;
let testString = 'test test test test';
console.log('original', testString);
// global modifier in RegExp
let result = testString.replace(/t/g, function (match) {
count++;
return (count % 2 === 0) ? '' : match;
});
console.log('removed', result);
like this?
var text = "This is a test!"
var result = ""
var rest = ""
for(var i = 0; i < text.length; i++){
if( (i%2) != 0 ){
result += text[i]
} else{
rest += text[i]
}
}
console.log(result+rest)
Maybe with split, filter and join:
const remaining = myString.split('').filter((char, i) => i % 2 !== 0).join('');
const deleted = myString.split('').filter((char, i) => i % 2 === 0).join('');
You could take an array and splice and push each second item to the end of the array.
function encrypt(string) {
var array = [...string],
i = 0,
l = array.length >> 1;
while (i <= l) array.push(array.splice(i++, 1)[0]);
return array.join('');
}
console.log(encrypt("This is a test!"));
function encrypt(text) {
text = text.split("");
var removed = []
var encrypted = text.filter((letter, index) => {
if(index % 2 == 0){
removed.push(letter)
return false;
}
return true
}).join("")
return {
full: encrypted + removed.join(""),
encrypted: encrypted,
removed: removed
}
}
console.log(encrypt("This is a test!"))
Splice does not work, because if you remove an element from an array in for loop indexes most probably will be wrong when removing another element.
I don't know how much you care about performance, but using regex is not very efficient.
Simple test for quite a long string shows that using filter function is on average about 3 times faster, which can make quite a difference when performed on very long strings or on many, many shorts ones.
function test(func, n){
var text = "";
for(var i = 0; i < n; ++i){
text += "a";
}
var start = new Date().getTime();
func(text);
var end = new Date().getTime();
var time = (end-start) / 1000.0;
console.log(func.name, " took ", time, " seconds")
return time;
}
function encryptREGEX(text) {
let removedText = '';
const replacedText1 = text.replace(/(.)(.)?/g, (_, firstChar, secondChar) => {
// in case the match was at the end of the string,
// and the string has an odd number of characters:
if (!secondChar) secondChar = '';
// remove the firstChar from the string, while adding it to removedText:
removedText += firstChar;
return secondChar;
});
return replacedText1 + removedText;
}
function encrypt(text) {
text = text.split("");
var removed = "";
var encrypted = text.filter((letter, index) => {
if(index % 2 == 0){
removed += letter;
return false;
}
return true
}).join("")
return encrypted + removed
}
var timeREGEX = test(encryptREGEX, 10000000);
var timeFilter = test(encrypt, 10000000);
console.log("Using filter is faster ", timeREGEX/timeFilter, " times")
Using actually an array for storing removed letters and then joining them is much more efficient, than using a string and concatenating letters to it.
I changed an array to string in filter solution to make it the same like in regex solution, so they are more comparable.

Compress characters aabbbcccc+++ to a#2b#3c#4+#3 in javascript

the above question is asked at an interview, the code must accept input like aabbbcccc+++ and should output a#2b#3c#4+#3 based on the number of strings occurrences.
You can use regex and captured in replace function.
(.)\1+ - Here . means match anything \1+ this means match the same character match by (.) one or more time. Than in the callback function we are returning concatenation first and length of match and #
let str = `aabbbcccc+++`
let op = str.replace(/(.)\1+/g, function(match,first){
return first+'#'+match.length;
})
console.log(op)
You can try regex method or you can use the snippet below
Basic loop
function compress(str) {
let newstr = "";
let count = 1;
let index = 0;
for (let i = 0; i <= str.length; i++) {
if (str.charAt(i) === str.charAt(i + 1)) {
count += 1;
} else {
newstr += `${str.charAt(i)}#${count}`;
count = 1;
}
}
console.log(newstr);
}
compress("aaaabbbbbccccc++++");
Use the regex method using above snippet https://stackoverflow.com/a/54326492/7444617

Swap Case on javascript

I made a script that changes the case, but result from using it on text is exactly the same text, without a single change. Can someone explain this?
var swapCase = function(letters){
for(var i = 0; i<letters.length; i++){
if(letters[i] === letters[i].toLowerCase()){
letters[i] = letters[i].toUpperCase();
}else {
letters[i] = letters[i].toLowerCase();
}
}
console.log(letters);
}
var text = 'So, today we have REALLY good day';
swapCase(text);
Like Ian said, you need to build a new string.
var swapCase = function(letters){
var newLetters = "";
for(var i = 0; i<letters.length; i++){
if(letters[i] === letters[i].toLowerCase()){
newLetters += letters[i].toUpperCase();
}else {
newLetters += letters[i].toLowerCase();
}
}
console.log(newLetters);
return newLetters;
}
var text = 'So, today we have REALLY good day';
var swappedText = swapCase(text); // "sO, TODAY WE HAVE really GOOD DAY"
You can use this simple solution.
var text = 'So, today we have REALLY good day';
var ans = text.split('').map(function(c){
return c === c.toUpperCase()
? c.toLowerCase()
: c.toUpperCase()
}).join('')
console.log(ans)
Using ES6
var text = 'So, today we have REALLY good day';
var ans = text.split('')
.map((c) =>
c === c.toUpperCase()
? c.toLowerCase()
: c.toUpperCase()
).join('')
console.log(ans)
guys! Get a little simplier code:
string.replace(/\w{1}/g, function(val){
return val === val.toLowerCase() ? val.toUpperCase() : val.toLowerCase();
});
Here is an alternative approach that uses bitwise XOR operator ^.
I feel this is more elegant than using toUppserCase/ toLowerCase methods
"So, today we have REALLY good day"
.split("")
.map((x) => /[A-z]/.test(x) ? String.fromCharCode(x.charCodeAt(0) ^ 32) : x)
.join("")
Explanation
So we first split array and then use map function to perform mutations on each char, we then join the array back together.
Inside the map function a RegEx tests if the value is an alphabet character: /[A-z]/.test(x) if it is then we use XOR operator ^ to shift bits. This is what inverts the casing of character. charCodeAt convert char to UTF-16 code. XOR (^) operator flips the char. String.fromCharCode converts code back to char.
If RegEx gives false (not an ABC char) then the ternary operator will return character as is.
References:
String.fromCharCode
charCodeAt
Bitwise operators
Ternary operator
Map function
One liner for short mode code wars:
let str = "hELLO wORLD"
str.split("").map(l=>l==l.toLowerCase()?l.toUpperCase():l.toLowerCase()).join("")
const swapCase = (myString) => {
let newString = ''; // Create new empty string
if (myString.match(/[a-zA-Z]/)) { // ensure the parameter actually has letters, using match() method and passing regular expression.
for (let x of myString) {
x == x.toLowerCase() ? x = x.toUpperCase() : x = x.toLowerCase();
newString += x; // add on each conversion to the new string
}
} else {
return 'String is empty, or there are no letters to swap.' // In case parameter contains no letters
}
return newString; // output new string
}
// Test the function.
console.log(swapCase('Work Today Was Fun')); // Output: wORK tODAY wAS fUN
console.log(swapCase('87837874---ABCxyz')); // Output: 87837874---abcXYZ
console.log(swapCase('')); // Output: String is empty, or there are no letters to swap.
console.log(swapCase('12345')); // Output: String is empty, or there are no letters to swap.
// This one will fail. But, you can wrap it with if(typeof myString != 'number') to prevent match() method from running and prevent errors.
// console.log(swapCase(12345));
This is a solution that uses regular expressions. It matches each word-char globally, and then performs a function on that matched group.
function swapCase(letters) {
return letters.replace( /\w/g, function(c) {
if (c === c.toLowerCase()) {
return c.toUpperCase();
} else {
return c.toLowerCase();
}
});
}
#this is a program to convert uppercase to lowercase and vise versa and returns the string.
function main(input) {
var i=0;
var string ='';
var arr= [];
while(i<input.length){
string = input.charAt(i);
if(string == string.toUpperCase()){
string = string.toLowerCase();
arr += string;
}else {
string = string.toUpperCase();
arr += string;
}
i++;
}
console.log(arr);
}
Split the string and use the map function to swap the case of letters.
We'll get the array from #1.
Join the array using join function.
`
let str = 'The Quick Brown Fox Jump Over A Crazy Dog'
let swapedStrArray = str.split('').map(a => {
return a === a.toUpperCase() ? a.toLowerCase() : a.toUpperCase()
})
//join the swapedStrArray
swapedStrArray.join('')
console.log('swapedStrArray', swapedStrArray.join(''))
`
A new solution using map
let swappingCases = "So, today we have REALLY good day";
let swapping = swappingCases.split("").map(function(ele){
return ele === ele.toUpperCase()? ele.toLowerCase() : ele.toUpperCase();
}).join("");
console.log(swapping);
As a side note in addition to what has already been said, your original code could work with just some minor modifications: convert the string to an array of 1-character substrings (using split), process this array and convert it back to a string when you're done (using join).
NB: the idea here is to highlight the difference between accessing a character in a string (which can't be modified) and processing an array of substrings (which can be modified). Performance-wise, Fabricator's solution is probably better.
var swapCase = function(str){
var letters = str.split("");
for(var i = 0; i<letters.length; i++){
if(letters[i] === letters[i].toLowerCase()){
letters[i] = letters[i].toUpperCase();
}else {
letters[i] = letters[i].toLowerCase();
}
}
str = letters.join("");
console.log(str);
}
var text = 'So, today we have REALLY good day';
swapCase(text);

How can i match and replace a string and its before one letter in javascript?

var str="itss[BACK][BACK][BACK][BACK][BACK][BACK] it's a test stringgg[BACK][BACK]";
var word = '[BACK]';
var substrings = str.split(word);
var cnt= substrings.length - 1;
for(var i = 0;i<cnt;i++){
str = str.replace(/.{1}\[BACK\]{1}/i,""); //remove backspace and one character before it.
}
The above script returns something like "[BACK it's a test string" I need to get this result as "it's a test string" please help me....
It's easier to do this without a regex actually.
String.prototype.replaceFromIndex=function(index, length, replace) {
return this.substr(0, index) + replace + this.substr(index+length);
}
var search = '[BACK]';
var str="itss[BACK][BACK][BACK][BACK][BACK][BACK] it's a test stringgg[BACK][BACK]";
while((index = str.indexOf(search)) >= 0){
str = str.replaceFromIndex(index-1, search.length+1, '');
}
alert(str);
Check http://jsfiddle.net/fRThH/2/ for a working example.
Wrap it in a function and you are ready to go!
Courtesy to Cem Kalyoncu ( https://stackoverflow.com/a/1431113/187018 ) for a slightly modified version of String.prototype.replaceAt
My idea is to count all the backspaces [BACK] and then replace them with an empty string one by one:
var str="itss[BACK][BACK][BACK][BACK][BACK][BACK] it's a test stringgg[BACK][BACK]";
var backspaces = str.match(/\[BACK\]/g).length;
for(i=0; i<backspaces; i++)
{
str = str.replace(/.?\[BACK\]/, '');
}
document.write( str );
working example: jsFiddle
If I understood correctly
var dat = str.split('[BACK]').filter(function(e){return e})[1];
here is the working demo.
One of the problems that I found out was that you didn't set a condition in which you would not have to remove the first character when the string '[BACK]' is in position zero.
Well, the solution I am posting here first search for the position of the first '[BACK]' string, and then creates a substring of the characters that we want to remove, so, if there is a character before the string '[BACK]', it is included in the substring. Then, the substring is removed from the main string, and it continues looping until all the '[BACK]' s are removed.
var str = "itss[BACK][BACK][BACK][BACK][BACK][BACK] it's a test stringgg[BACK][BACK]";
var word = '[BACK]';
var substrings = str.split(word);
var cnt = substrings.length - 1;
for (i = 0; i < cnt; i++) {
pos = str.search("[BACK]");
if (pos - 1 > 0) {
str = str.replace(str.substring(pos - 2, pos + 5), '');
} else {
str = str.replace(str.substring(pos - 1, pos + 5), '');
}
}
Here is the code in jsfiddle:

Categories

Resources