Replace nth occurrence javascript - javascript

in this example string '1,2,3,4,5' I am trying to capture and replace the 3rd occurence of the comma , character
this code here
'1,2,3,4,5'.match(/(?:[^,]*,){2}[^,]*(,)/)
matches 1,2,3 and the comma im looking for
but not sure how to replace just the comma
'1,2,3,4,5'.replace(/(?:[^,]*,){2}[^,]*(,)/, "$")
replaces everything before 4 giving $4,5
i just want a string result like 1,2,3$4,5 for example
I have achieved this task in two different ways, with array split and slice and with a String#replace that takes a callback
//splice
let parts = [];
let str = "1,2,3,4,5";
let formatted = ((parts = str.split(",")).slice(0,3)).join("-") + ' ' + parts.slice(3).join(":")
​
//callback
let str = "1,2,3,4,5";
str.replace(/,/g, (() => {
let count = 0;
return (match, position) => {
count += 1;
if(count == 3) return ' ';
else if(count < 3) return '-';
else return ':';
});
})())
Is this even possible with a plain String#replace?

You can use capturing group and replace by first capturing group
.replace(/((?:[^,]*,){2}[^,]*),/g, "$1:");
^ ^
The captured group will capture the matched string except the third comma which is $1 in the replacement string.
console.log('1,2,3,4,5,2,3,4,5,2,3,4,5'.replace(/((?:[^,]*,){2}[^,]*),/g, "$1:"));

Related

JavaScript remove a character from a string and remove the previous character

How do I remove a character from a string and remove the previous character as well?
Example:
"ABCXDEXFGHXIJK"
I want to split the string by "X" and remove the previous character which returns
"ABDFGIJK" // CX, EX, HX are removed
I found this thread but it removes everything before rather than a specific amount of characters: How to remove part of a string before a ":" in javascript?
I can run a for loop but I was wondering if there was a better/simpler way to achieve this
const remove = function(str){
for(let i = 0; i < str.length; i++){
if(str[i] === "X") str = str.slice(0, i - 1) + str.slice(i + 1);
}
return str
}
console.log(remove("ABCXDEXFGHXIJK")) // ABDFGIJK
You can use String.prototype.replace and regex.
"ABCXDEXFGHXIJK".replace(/.X/g, '')
The g at the end is to replace every occurrence of .X. You can use replaceAll as well, but it has less support.
"ABCXDEXFGHXIJK".replaceAll(/.X/g, '')
If you want it to be case insensitive, use the i flag as well.
"ABCXDEXFGHXIJK".replace(/.x/gi, '')
The simplest way is to use a regular expression inside replace.
"ABCXDEXFGHXIJK".replace(/.X/g, "")
.X means "match the combination of X and any single character before it, g flag after the expression body repeats the process globally (instead of doing it once).
While not the most computationally efficient, you could use the following one-liner that may meet your definition of "a better/simpler way to achieve this":
const remove = str => str.split("X").map((ele, idx) => idx !== str.split("X").length - 1 ? ele.slice(0, ele.length - 1) : ele).join("");
console.log(remove("ABCXDEXFGHXIJK"));
Maybe you can use recursion.
function removeChar(str, char){
const index = str.indexOf(char);
if(index < 0) return str;
// removes 2 characters from string
return removeChar(str.split('').splice(index - 2, index).join());
}
Try this way (Descriptive comments are added in the below code snippet itself) :
// Input string
const str = "ABCXDEXFGHXIJK";
// split the input string based on 'X' and then remove the last item from each element by using String.slice() method.
const splittedStrArr = str.split('X').map(item => item = item.slice(0, -1));
// Output by joining the modified array elements.
console.log(splittedStr.join(''))
By using RegEx :
// Input string
const str = "ABCXDEXFGHXIJK";
// Replace the input string by matching the 'X' and one character before that with an empty string.
const modifiedStr = str.replace(/.X/g, "")
// Output
console.log(modifiedStr)

What's wrong with the first element in HOF in JS?

Here I have a string with repeated chars,
I want to get the string without repetition, so I used map with specific index, but I don't know what's wrong with the 1st repeated char, when I used slice(i+1,1) all thing was good, but when I used slice(i,1) also all thing was good except the first repeated char.
The output of the 1st code is : elzero
The output of the 2nd code is : eelzero
What's the problem?
Here's the two codes:
let myString = "EElllzzzzzzzeroo";
let elzero = myString
.split("")
.map(function(ele, i = 1, myString) {
console.log(i);
if (myString[i] === myString[i + 1]) {
return myString[i + 1].slice(i + 1, 1);
} else {
return myString[i];
}
})
.join("");
console.log(elzero);
// Elzero
And here's the second:
let myString = "EElllzzzzzzzeroo";
let elzero = myString
.split("")
.map(function(ele, i = 1, myString) {
console.log(i);
if (myString[i] === myString[i + 1]) {
return myString[i].slice(i, 1);
} else {
return myString[i];
}
})
.join("");
console.log(elzero);
// EElzero
Your first code block only works because your .slice() happens to be returning empty strings. You really don't need to use .slice() at all, since all it does is generate an empty string which is then removed when you use .join(). The .slice() call does NOT update/remove an element like .splice() on an array does.
In your second code block, you're doing:
myString[i].slice(i, 1);
If i is 0 then you are on the first character in your string, so myString[0] is "E". Here, .slice(0, 1) says, give me the string that starts at index 0 up to, but not including index 1. This results in "E" being returned.
For all of your subsequent calls myString[i] gives you back one character (so it only has one index, 0), but you're trying to use .slice() to get a portion of your string from indexes that don't exist as i is bigger than your index. Moreover, i is bigger than your second argument, so when i is 1, you're asking to get get the string portion from index 1 (which doesn't exist) up to but not including 1, which results in an empty string. When i is 2, its a similar situation, which results in an empty string.
What you should be doing is removing the use of .slice() altogether, and instead return an empty string when you want to omit the character:
let myString = "EElllzzzzzzzeroo";
let elzero = myString
.split("")
.map(function(ele, i, myString) {
if (ele === myString[i + 1]) { // if current char (ele) equals the next char (myString[i+1]), then "remove" the current char by mapping it to an empty string (this is removed when we `.join("")`)
return "";
} else {
return ele;
}
})
.join("");
console.log(elzero); // Elzero
More concisely, you can rewrite this with arrow functions and a ternary like so. You can also use Array.from() to iterate the code points (ie: characters) within your string, and use the second argument as the mapping function:
const myString = "EElllzzzzzzzeroo";
const elzero = Array.from(
myString,
(ele, i) => ele === myString[i + 1] ? "" : ele
).join("");
console.log(elzero); // Elzero
Alternatively, using a different approach, you can use .replace() with a regular expression to remove repeated characters:
const myString = "EElllzzzzzzzeroo";
const elzero = myString.replace(/(.)\1*/g, '$1')
console.log(elzero); // Elzero
The (.) captures a character and groups it, the \1* is a backreference that matches zero or more of the grouped character repeated, and the "$1" replaces the matched characters with the singular grouped character.
Since you are returning myString[i], not myString[i+1], you have to compare myString[i] with myString[i-1]:
let myString = "EElllzzzzzzzeroo";
let elzero = myString
.split("")
.map(function(ele, i = 1, myString) {
console.log(i);
// if (myString[i] === myString[i + 1]) {
if (myString[i-1] === myString[i]) {
return myString[i].slice(i, 1);
} else {
return myString[i];
}
})
.join("");
console.log(elzero);
// EElzero

How to remove the (.) in a string and then display every alphabetic character with a dot

I would like to have a a function who takes a string a parameter, removes the dots, loops trough every alphabetic character and display like this (A.B.C.) when input is (A..B..C) for example.
How can I build this function?
Here for I have the next function in mind, unfortunately is not working I get a output result like this (hfff) when input string is "h..f.ff", would like to have this output (H.F.F.F)
function filter (initials) {
let result = initials.replace(/\./g, '')
let i;
for (i = 0; i < result.length; i++) {
result[i] + ".";
}
return result
console.log(result)
}
const initials = "h..f.ff"
console.log(filter(initials))
You could use split, map and join
function filter(initials) {
return initials.replace(/[^a-z]/gi, '') // Remove non-letters
.toUpperCase()
.split('') // Convert to an Array
.map(l => l + '.') // Add dots
.join(''); // Join
}
const initials = "h..f.ff";
console.log(filter(initials));
You need to assign this
result[i] + ".";
to something. Do:
let i,newresult;
for (i = 0; i < result.length; i++) {
newresult += result[i] + ".";
}
well you can:
make the string uppercase
split the string char-by-char
filter only letters
join using "."
function format(string){
return string.toUpperCase()
.split("")
.filter(c => /[a-zA-Z]/.test(c))
.join(".")
}
format("h..f.ff") // "H.F.F.F"
Use replaceAll to remove all . char with nothing.
Then from that string, make all letters uppercase.
From that string, split the whole word up into and array of letters using split (Each piece of the string on each side of the parameter passed to split gets turned into an element in a new array. if you leave the parameter blank, it's just each character in the string)
Finally join each those elements together with a . between them using join
function filter (initials) {
initials=initials.replaceAll('.','');
initials=initials.toUpperCase();
initials=initials.split('');
initials=initials.join('.');
return initials;
}
var test = "h..f..t....e.Z";
console.log(filter(test));
Thanks #blex for the snippet advice

Replace all “?” by “&” except first

I’d would to replace all “?” by “&” except the first one by javascript. I found some regular expressions but they didn’t work.
I have something like:
home/?a=1
home/?a=1?b=2
home/?a=1?b=2?c=3
And I would like:
home/?a=1
home/?a=1&b=2
home/?a=1&b=2&c=3
Someone know how to I can do it?
Thanks!
I don't think it's possible with regex but you can split the string and then join it back together, manually replacing the first occurance:
var split = 'home/?a=1?b=2'.split('?'); // [ 'home/', 'a=1', 'b=2' ]
var replaced = split[0] + '?' + split.slice(1).join('&') // 'home/?a=1&b=2'
console.log(replaced);
You could match from the start of the string not a question mark using a negated character class [^?]+ followed by matching a question mark and capture that in the first capturing group. In the second capturing group capture the rest of the string.
Use replace and pass a function as the second parameter where you return the first capturing group followed by the second capturing group where all the question marks are replaced by &
let strings = [
"home/?a=1",
"home/?a=1?b=2",
"home/?a=1?b=2?c=3"
];
strings.forEach((str) => {
let result = str.replace(/(^[^?]+\?)(.*)/, function(match, group1, group2) {
return group1 + group2.replace(/\?/g, '&')
});
console.log(result);
});
You can split it by "?" and then rewrap the array:
var string = "home/?a=1?b=2";
var str = string.split('?');
var new = str[0] + '?'; // text before first '?' and first '?'
for( var x = 1; x < str.length; x++ ) {
new = new + str[x];
if( x != ( str.length - 1 ) ) new = new + '&'; //to avoid place a '&' after the string
}
You can use /([^\/])\?/ as pattern in regex that match any ? character that isn't after / character.
var str = str.replace(/([^\/])\?/g, "$1&");
var str = "home/?a=1\nhome/?a=1?b=2\nhome/?a=1?b=2?c=3\n".replace(/([^\/])\?/g, "$1&");
console.log(str);

Recombine capture groups in single regexp?

I am trying to handle input groups similar to:
'...A.B.' and want to output '.....AB'.
Another example:
'.C..Z..B.' ==> '......CZB'
I have been working with the following:
'...A.B.'.replace(/(\.*)([A-Z]*)/g, "$1")
returns:
"....."
and
'...A.B.'.replace(/(\.*)([A-Z]*)/g, "$2")
returns:
"AB"
but
'...A.B.'.replace(/(\.*)([A-Z]*)/g, "$1$2")
returns
"...A.B."
Is there a way to return
"....AB"
with a single regexp?
I have only been able to accomplish this with:
'...A.B.'.replace(/(\.*)([A-Z]*)/g, "$1") + '...A.B.'.replace(/(\.*)([A-Z]*)/g, "$2")
==> ".....AB"
If the goal is to move all of the . to the beginning and all of the A-Z to the end, then I believe the answer to
with a single regexp?
is "no."
Separately, I don't think there's a simpler, more efficient way than two replace calls — but not the two you've shown. Instead:
var str = "...A..B...C.";
var result = str.replace(/[A-Z]/g, "") + str.replace(/\./g, "");
console.log(result);
(I don't know what you want to do with non-., non-A-Z characters, so I've ignored them.)
If you really want to do it with a single call to replace (e.g., a single pass through the string matters), you can, but I'm fairly sure you'd have to use the function callback and state variables:
var str = "...A..B...C.";
var dots = "";
var nondots = "";
var result = str.replace(/\.|[A-Z]|$/g, function(m) {
if (!m) {
// Matched the end of input; return the
// strings we've been building up
return dots + nondots;
}
// Matched a dot or letter, add to relevant
// string and return nothing
if (m === ".") {
dots += m;
} else {
nondots += m;
}
return "";
});
console.log(result);
That is, of course, incredibly ugly. :-)

Categories

Resources