replace substring between two substrings on every match [duplicate] - javascript

This question already has answers here:
Regular expression: same character 3 times
(3 answers)
Closed 2 years ago.
Is there a faster built-in function in JavaScript to replace a substring2 between two substrings with a sequence of numbers the length of substring2, than looping the whole string and replace it by hand.
example:
substring before: "before"
substring after: "after"
if substring2 is length of 3 => replace with string 011
if substring2 is length of 6 => replace with string 999999
string:
"beforeoooafter beforeaftebefore123456afteradf"
ooo would be the substring2 and 123456 too
ooo => 011 (because length 3)
123456 => 999999 (because length 6)
substring2 is a match between the string before and after
result:
"before011after beforeaftebefore999999afteradf"

You can use a Regular Expression and a replace function:
const input = "beforeoooafter beforeaftebefore123456afteradf";
const expectedOutput = "before011after beforeaftebefore999999afteradf";
const output = input.replace(/(before(?:(?!before|after).)*after)/g, function(m) {
const before = 'before';
const after = 'after';
const middle = m.substr(before.length, m.length - after.length - before.length);
if (middle.length === 3) {
return before + '011' + after;
} else if (middle.length === 6) {
return before + '999999' + after;
}
return m;
});
console.log(output);
console.log(output === expectedOutput);

Related

In JS, count the number of occurence found in a string [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 23 days ago.
Improve this question
I've this piece of code that will count the number of occurrences found in a given string.
But it will only count the number of unique special characters in the string.
How can I change this behavior ?
It should give me 3 and not 1 as I have 3 spaces.
Thanks.
var string = 'hello, i am blue.';
var specialChar = [' ', '!'];
let count = 0
specialChar.forEach(word => {
string.includes(word) && count++
});
console.log(count);
What you are doing is iterating over specialChar, which yields two iterations: the first iteration will check if ' ' is included in the string which is true and thus increments count, and the second iteration will check if '!' is included in the string which is not the case hence you get 1.
What you should actually do is iterate through the string and check if each character is included in the specialChar array. Here is how you can do that with the minimum changes made (the code can be improved and made clearer).
Note: .split("") splits the string to an array of its characters.
var string = 'hello, i am blue.';
var specialChar = [' ', '!'];
let count = 0
string.split("").forEach(char => {
specialChar.includes(char) && count++
});
console.log(count);
Since you're using an array of matches [" ", "!"] you need as an output - and Object with the counts, i.e: {" ": 5, "!": 2}.
Here's two examples, one using String.prototype.match(), and the other using Spread Syntax ... on a String
Using Match
and Array.prototype.reduce() to reduce your initial Array to an Object result
const string = 'hello, i am blue. And this is an Exclamation! Actually, two!';
const specialChar = [' ', '!'];
const regEscape = v => v.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
const count = specialChar.reduce((ob, ch) => {
ob[ch] = string.match(new RegExp(regEscape(ch), "g")).length;
return ob;
}, {}); // << This {} is the `ob` accumulator object
console.log(count);
Using String spread ...
to convert the string to an array of Unicode code-points sequences / symbols
const string = 'hello, i am blue. And this is an Exclamation! Actually, two!';
const specialChar = [' ', '!'];
const count = [...string].reduce((ob, ch) => {
if (!specialChar.includes(ch)) return ob;
ob[ch] ??= 0;
ob[ch] += 1;
return ob;
}, {}); // << This {} is the `ob` accumulator object
console.log(count);
One way to count characters in a string is to split the string by the character and then count the parts and subtract one.
var string = 'hello! i am blue!';
var specialChar = [' ', '!'];
let count = 0
specialChar.forEach(char => {
count += string.split(char).length - 1
});
console.log(count);
Or using RegExp being sure to escape anything that is considered a special character.
function escapeRegex(v) {
return v.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
}
function countChars(str, chars) {
const escapedChars = escapeRegex(chars.join(''));
const regex = new RegExp(`[${escapedChars}]`, "g");
return str.match(regex)?.length || 0;
}
console.log(countChars('hello! i am blue!', [' ', '!']));
The fastest version turns out to be one that counts the char in a word using indexOf
function countCharsIndexOf(str, char) {
let num = 0;
let pos = str.indexOf(char);
while (pos > -1) {
pos = str.indexOf(char, pos + 1);
num++;
}
return num;
}
function countAllCharsIndexOf(str, chars) {
return chars.reduce(
(acc, char) => acc + countCharsIndexOf(str, char),
0
);
}
console.log(countAllCharsIndexOf('hello! i am blue!', [' ', '!']));

NodeJS How to pad the end of numbers with . and zeros? [duplicate]

This question already has answers here:
Rounding numbers to 2 digits after comma
(10 answers)
Closed 3 years ago.
Let's say we have the number 300 and I wanted it to be padded to end as 300.000
Or the number 23,5 would be something like 23.500
Hope it will help, details are in comments.
function formating(n) {
// Convert number into a String
const str = n.toString();
// Find the position of the dot.
const dotPosition = str.search(/\./);
// Return string with the pad.
if (dotPosition === -1) {
return str += ".000";
} else {
const [part1, part2] = str.split('.');
return part1 + '.' + part2.padEnd(3, "0");
}
}

A operation to split a string to several part [duplicate]

This question already has answers here:
How can I split a string into segments of n characters?
(17 answers)
Closed 3 years ago.
I want to show the type is 123 456 789 after I get the string 123456789. I used the method like following, but I do not think it is a great way, so does anyone has a better way ?
let num = '123456789'
let result = num.slice(0,3)+ ' '+num.slice(3,6)+ ' '+num.slice(6,9) // result = '123 456 789'
You can use a global regular expression and match 3 digits, then join by spaces:
let num = '123456789';
const result = num
.match(/\d{3}/g)
.join(' ');
console.log(result);
Or, with .replace and lookahead for another digit:
let num = '123456789';
const result = num.replace(/\d{3}(?=\d)/g, '$& ');
console.log(result);
You do that using while loop and slice()
let str = '123456789';
function splitBy(str,num){
let result = '';
while(str.length > num){
result += str.slice(0,3) + ' ';
str = str.slice(3);
}
return result + str;
}
console.log(splitBy(str,3));
You can use Array.from() to return an array of chunks based on the split-length provided. Then use join() to concatenate them
let num = '123456789'
function getChunks(string, n) {
const length = Math.ceil(string.length / n);
return Array.from({ length }, (_, i) => string.slice(i * n, (i + 1) * n))
}
console.log(getChunks(num, 3).join(' '))
console.log(getChunks(num, 4).join(' '))

JavaScript regexp, not getting all matches, what am I missing here? [duplicate]

This question already has answers here:
How can I match overlapping strings with regex?
(6 answers)
Closed 4 years ago.
Let's say for example I have this simple string
let str = '5+81+3+16+42'
Now if I want to capture each plus sign with both numbers around it.
My attempt was as follows:
let matches = str.match(/\d+\+\d+/g);
What I got with that is:
['5+81', '3+16']
Why is it not matching the cases between?
['5+81', '81+3', '3+16', '16+42']
Your regex has to fulfill the whole pattern which is \d+\+\d+. It will first match 5+81, then the next character is a + which the pattern can not match because it should start with a digit. Then it can match 3+16 but it can not match the following +42 anymore given you ['5+81', '3+16'] as the matches.
Without a regex, you might use split and a for loop and check if the next value exists in the parts array:
let str = '5+81+3+16+42'
let parts = str.split('+');
for (let i = 0; i < parts.length; i++) {
if (undefined !== parts[i + 1]) {
console.log(parts[i] + '+' + parts[i + 1]);
}
}
When using more a recent version of Chrome which supports lookbehinds, you might use lookarounds with capturing groups:
(?<=(\d+))(\+)(?=(\d+))
See the regex demo
const regex = /(?<=(\d+))(\+)(?=(\d+))/g;
const str = `5+81+3+16+42`;
let m;
while ((m = regex.exec(str)) !== null) {
if (m.index === regex.lastIndex) {
regex.lastIndex++;
}
console.log(m[1] + m[2] + m[3]);
}
When the regular expression engine completes one iteration of a match, it "consumes" the characters from the source string. The first match of 5+81 leaves the starting point for the next match at the + sign after 81, so the next match for the expression begins at the 3.
Split string by + delimiter and use .reduce() to create new array contain target result.
let str = '5+81+3+16+42';
let arr = str.split('+').reduce((tot, num, i, arr) => {
i+1 < arr.length ? tot.push(num+"+"+arr[i+1]) : '';
return tot;
}, []);
console.log(arr);
You can do it using split and reduce without making things complex with regex.
let str = '5+81+3+16+42';
const array = str.split('+');
const splited = []
array.reduce((a, b) => {
splited.push(a+'+'+b)
return b
})
console.log(splited);

Clip off last digits from arrays

I have the following array
var arr = ['1234','23C','456','356778', '56']
I want to remove array elements which are less than 3 characters and greater than 4 characters. The final result should be as follows
arr = ['1234', '23C', '456']; //only 3 and 4 digits in the array.
Secondly, I want to do the following. if 'arr' has elements longer than 3 characters, I need to clip of by removing the last digit. The final 'data' array should look like this.
arr = ['123', '23C', '456'];
For the first part, you can just use filter to filter out numbers that aren't composed of 3 digits.
var arr = [1234, 234, 456, 356778, 56];
var result = arr.filter(function(num) {
return num < 1000 && num >= 100;
});
console.log(result);
For the second part, you can use map. Just convert the number to a string. If the length of it is greater than 3, take the substring composed of the first 3 elements of the string, then convert back to a number.
var data = [1234, 123, 4567, 3333];
var result = data.map(function(num) {
num = num.toString().substring(0, 3);
return parseInt(num);
});
console.log(result);
All You want is Array.filter and Array.map, and converting String to Number
var arr = [1234,234,456,356778, 56]
var newArr = arr.filter((num) => {
// convert number to string
var str = '' + num
// if length is 3 or 4 - return true (element will be in newArr)
return str.length === 3 && str.length === 4
})
and the second case
var newArr = arr.map((num) => {
var str = '' + num
// is str is longer than 3, cut it to length of 3
if(str.length > 3)
str = str.substring(0, 3)
// return str converted to number
return +str
})
function filterArray(arr,lowDigits,highDigits){
var newArr=[];
for(i=0;i<arr.length;i++){
val=arr[i];
length=val.length;
if(length>=lowDigits&&length<=highDigits){
if(length>lowDigits){
val=val.substring(0,lowDigits);
}
newArr.push(val);
}
}
return newArr;
}
var arr = ['1234','234','456','356778','56'];
arr=filterArray(arr,3,4);
console.log(arr);
To handle if a number is 3 or 4 digits, check if each number is in the range 100 <= num < 10000
let result = arr.filter(function(val) {
// is a 3 or 4 digit number
return 100 >= val && num < 10000;
});
To clip the four digits to 3 digits, we can divide all four digit numbers by 10 and convert them to an integer
let clippedResult = result.map(function(val) {
return val >= 1000 ? Math.floor(val / 10) : val
});
This solution converts the input array to a string of the form 1234,23C,456,356778,56, then finds the wanted elements using regexp.
var arr = ['1234','23C','456','356778', '56'];
console.log(String(arr).match(/\b\w{3}(?=\w?\b)/g));
In English:
Find all the substrings which start with a word boundary (\b, which will be after a comma, or the beginning of the string), then have three alphanumeric characters, and which looking ahead ((?=) may (?) have one additional character before the next word boundary (comma or end of string).
And yes, this will work with string elements, as long as the strings are composed of alphanumerics (in other words, things which won't break the word break (\b) logic.
let isValidElement = updated_ImportDetails.ImportData.filter(function (num) {
// is a 3 or 4 digit number
return num.length > 2 && num.length <4 ;
});
var result = isValidElement.map(function (num) {
num = num.substring(0, 3);
return num;
});
result = result.filter(function (elem, index, self) {
return index == self.indexOf(elem);
}) //removes duplicates from the array
This worked for me.

Categories

Resources