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
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"));
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.
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
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);
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: