regex replace for multiple string array javascript - javascript

I have a array of string and the patterns like #number-number anywhere inside a string.
Requirements:
If the # and single digit number before by hyphen then replace # and add 0. For example, #162-7878 => 162-7878, #12-4598866 => 12-4598866
If the # and two or more digit number before by hyphen then replace remove #. For example, #1-7878 => 01-7878.
If there is no # and single digit number before by hyphen then add 0. For example, 1-7878 => 01-7878.
I got stuck and how to do in JavaScript. Here is the code I used:
let arrstr=["#12-1676","#02-8989898","#676-98908098","12-232","02-898988","676-98098","2-898988", "380100 6-764","380100 #6-764","380100 #06-764"]
for(let st of arrstr)
console.log(st.replace(/#?(\d)?(\d-)/g ,replacer))
function replacer(match, p1, p2, offset, string){
let replaceSubString = p1 || "0";
replaceSubString += p2;
return replaceSubString;
}

I suggest matching # optionally at the start of string, and then capture one or more digits before - + a digit to later pad those digits with leading zeros and omit the leading # in the result:
st.replace(/#?\b(\d+)(?=-\d)/g, (_,$1) => $1.padStart(2,"0"))
See the JavaScript demo:
let arrstr=["#12-1676","#02-8989898","#676-98908098","12-232","02-898988","676-98098","2-898988", "380100 6-764","380100 #6-764","380100 #06-764"]
for(let st of arrstr)
console.log(st,'=>', st.replace(/#?\b(\d+)(?=-\d)/g, (_,$1) => $1.padStart(2,"0") ))
The /#?\b(\d+)(?=-\d)/g regex matches all occurrences of
#? - an optional # char
\b - word boundary
(\d+) - Capturing group 1: one or more digits...
(?=-\d) - that must be followed with a - and a digit (this is a positive lookahead that only checks if its pattern matches immediately to the right of the current location without actually consuming the matched text).

Using the unary operator, here's a two liner replacer function.
const testValues = ["#162-7878", "#12-4598866", "#1-7878", "1-7878"];
const re = /#?(\d+?)-(\d+)/;
for(const str of testValues) {
console.log(str.replace(re, replacer));
}
function replacer(match, p1, p2) {
p1 = +p1 < 10 ? `0${p1}` : p1;
return `${p1}-${p2}`;
}

let list_of_numbers =["#1-7878", "#162-7878", "#12-1676","#02-8989898","#676-98908098","12-232","02-898988","676-98098","2-898988"]
const solution = () => {
let result = ''
for (let number of list_of_numbers) {
let nums = number.split('-')
if (nums[0][0] == '#' && nums[0].length > 2) {
result = `${nums[0].slice(1, number.length-1)}-${nums[1]}`
console.log(result)
} else if (nums[0][0] == '#' && nums[0].length == 2) {
result = `${nums[0][0] = '0'}${nums[0][1]}-${nums[1]}`
console.log(result)
} else {
console.log(number)
}
}
}

I think a simple check is what you should do with the match function.
let arrstr=["#12-1676","#0-8989898","#676-98908098","12-232","02-898988","676-98098","2-898988"];
const regex = /#\d-/g;
for(i in arrstr){
var found = arrstr[i].match(regex);
if(found){
arrstr[i]=arrstr[i].replace("#","0")
}else{
arrstr[i]=arrstr[i].replace("#","")
}
}
console.log(arrstr);
or if you really want to stick with the way you have it.
let arrstr=["#12-1676","#02-8989898","#6-98908098","12-232","02-898988","676-98098","2-898988"]
for(let st of arrstr)
console.log(st.replace(/#(\d)?(\d-)/g ,replacer))
function replacer(match, p1, p2, offset, string){
let replaceSubString = p1 || "0";
replaceSubString += p2;
return replaceSubString;
}
remove the '?' from the regex so its not #? but just #

Related

Partially mask email address - javascript

How can I partially hide email address like this in Javascript?
examplemail#domain.com => ex**pl**ai*#domain.com
I have modify the below code, but can get the result that I need, it's just return this result:
exam*******#domain.com
email.replace(/(.{4})(.*)(?=#)/, function (gp1, gp2, gp3) {
for (let i = 0; i < gp3.length; i++) {
gp2 += "*";
}
return gp2;
});
You could seach for a group of four characters and replace a group of two until you found an # sign-
const
mask = string => string.replace(
/(..)(.{1,2})(?=.*#)/g,
(_, a, b) => a + '*'.repeat(b.length)
);
console.log(mask('examplemail#domain.com'));
This would be one way to solve your problem:
function f(mail) {
let parts = mail.split("#");
let firstPart = parts[0];
let encrypt = firstPart.split("");
let skip = 2;
for (let i = 0; i < encrypt.length; i += 1) {
if (skip > 0) {
skip--;
continue;
}
if (skip === 0) {
encrypt[i] = "*";
encrypt[i + 1] = "*";
skip = 2;
i++;
}
}
let encryptedMail = `${encrypt.join("")}#${parts.slice(1)}`;
return encryptedMail;
}
Simply do this
function maskFunc(x) {
var res = x.replace(/(..)(.{1,2})(?=.*#)/g,
(beforeAt, part1, part2) => part1 + '*'.repeat(part2.length)
);
return res
}
console.log(maskFunc('emailid#domain.com'));
As a regex for the accepted answer, I would suggest making sure to match only a single # sign by making use of a negated character class [^\s#] matching any char except a whitespace char or an # itself.
This way you might also use it for multiple email addresses, because using (?=.*#) with multiple # signs can give unexpected results.
([^\s#]{2})([^\s#]{1,2})(?=[^\s#]*#)
Regex demo
In the pattern that you tried, you matched 4 times any char using (.{4}). Repeating 4 chars might be done using a positive lookbehind. Then you could get the match only without groups.
First assert a whitespace boundary to the left. Then start with an offset of 2 chars, optionally repeated by 4 chars.
Then match 1 or 2 chars, asserting an # to the right.
const partialMask = s => s.replace(
/(?<=(?<!\S)[^\s#]{2}(?:[^\s#]{4})*)[^\s#]{1,2}(?=[^\s#]*#)/g,
m => '*'.repeat(m.length)
);
console.log(partialMask("examplemail#domain.com"));
If you want to only replace the digits close to the # and allow it to add * base on the length, you can do this
const separatorIndex = email.indexOf('#');
if (separatorIndex < 3)
return email.slice(0, separatorIndex).replace(/./g, '*')
+ email.slice(separatorIndex);
const start = separatorIndex - Math.round(Math.sqrt(separatorIndex)) - 1;
const masked = email.slice(start, separatorIndex).replace(/./g, '*');
return email.slice(0, start) + masked + email.slice(separatorIndex);

RegEx replacing numbers greater than variable in Javascript

I have the string:
"selection1 selection2 selection3 selection4"
I am looking to remove all words that end in a number greater than a variable. For instance:
let str = "selection1 selection2 selection3 selection4";
let x = 2;
let regExp = RegExp(...);
let filtered = str.replace(regExp , ""); // should equal "selection1 selection2"
I came up with the following expression which selects all words that end in numbers greater than 29:
/(selection[3-9][0-9]|[1-9]\d{3}\d*)/gi
The result from this regEx on the string "selection1 selection 40" is [selection40]
I feel that I'm part of the way there.
Given that I'm dealing with single and double digit numbers and am looking to incorporate a variable, what regEx could help me alter this string?
You can use .replace with a callback:
let str = "selection5 selection1 selection2 selection3 selection4";
let x = 2;
let regex = /\s*\b\w+?(\d+)\b/g;
let m;
let repl = str.replace(regex, function($0, $1) {
return ($1 > x ? "" : $0);
}).trim();
console.log( repl );
Regex /\b\w+?(\d+)\b/g matches all the words ending with 1+ digits and captures digits in capture group #1 which we use inside the callback function to compare against variable x.
You can split by whitespace, then capture the group using Regex which gets the only the numeric part and filter it accordingly.
const str = "selection1 selection2 selection3 selection4";
const threshold = 2;
const pattern = /selection(\d+)/
const result = str
.split(' ')
.filter(x => Number(x.match(pattern)[1]) <= threshold)
.join(' ');
console.log(result);

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

RegEx: different initials format

I am using this piece of code to get the initials of the person's full name:
var name = "John Smith"; // for an example
var initials = name.match(/\b\w/g) || [];
initials = ((initials.shift() || '') + (initials.pop() || '')).toUpperCase();
// initials then returns "JS"
Now I need my initials to return the first letter of the first name and three letters of the last name ("JSMI" in the example above).
What should I alter in my regex in order to do that?
Also, if person would have two names (for example "John Michael Smith"), I need to get "JMSMI" as a result...
Any other solutions are welcome!
Try with Array#split() , substring() and Array#map
first you need split the string with space.
And get the single letter array[n-1] using sustring,
Then get the 3 letter on final argument of array
Map function iterate each word of your string
function reduce(a){
var c= a.split(" ");
var res = c.map((a,b) => b < c.length-1 ? a.substring(0,1) : a.substring(0,3))
return res.join("").toUpperCase()
}
console.log(reduce('John Michael Smith'))
console.log(reduce('John Smith'))
You may add a \b\w{1,3}(?=\w*$) alternative to your existing regex at the start to match 1 to 3 words chars in the last word of the string.
var name = "John Michael Smith"; //John Smith" => JSMI
var res = name.match(/\b\w{1,3}(?=\w*$)|\b\w/g).map(function (x) {return x.toUpperCase()}).join("");
console.log(res);
See the regex demo.
Regex details:
\b - a leading word boundary
\w{1,3} - 1 to 3 word chars (ASCII letters, digits or _)
(?=\w*$) - a positive lookahead requiring 0+ word chars followed with the end of string position
| - or
\b\w - a word char at the start of a word.
I tried to avoid capturing groups (and used the positive lookahead) to make the JS code necessary to post-process the results shorter.
Use split() and substr() to easily do this.
EDIT
Updated code to reflect the middle initial etc
function get_initials(name) {
var parts = name.split(" ");
var initials = "";
for (var i = 0; i < parts.length; i++) {
if (i < (parts.length - 1)) {
initials += parts[i].substr(0, 1);
} else {
initials += parts[i].substr(0, 3);
}
}
return initials.toUpperCase();
}
console.log(get_initials("John Michael Smith"));
My two cents with a reducer :)
function initials(name) {
return name.split(' ').reduce(function(acc, item, index, array) {
var chars = index === array.length - 1 ? 3 : 1;
acc += item.substr(0, chars).toUpperCase();
return acc;
}, '')
}
console.log(initials('John'));
console.log(initials('John Michael'));
console.log(initials('John Michael Smith'));
You may want use String.prototype.replace to drop following letters:
This regexp will match first 1 (or 3 for last name) letters in a word, and only keep it.
'John Smith'.replace(/(?:(\w)\w*\s+)|(?:(\w{3})\w*$)/g, '$1$2').toUpperCase()
const name = "John Michael Smith";
const initials = name.toUpperCase().split(/\s+/)
.map((x, i, arr) => x.substr(0, i === arr.length - 1 ? 3 : 1))
.join('');
console.log(initials);

Change char in a string in JavaScript

What regular expression should I use with the 'replace()' function in JavaScript to change every occurrence of char '_' in 0, but stop working as long as finding the char '.'?
Example:
_____323.____ ---> 00323._
____032.0____ --> 0032.0_
Are there ways more efficient than to use 'replace()'?
I am working with numbers. In particular, they can be both integer that float, so my string could never have two dots like in __32.12.32 or __31.34.45. At maximum just one dot.
What can I add in this:
/_(?=[\d_.])/g
to also find '_' followed by nothing?
Example: 0__ or 2323.43_
This does not work:
/_(?=[\d_.$])/g
You could use
str = str.replace(/[^.]*/,function(a){ return a.replace(/_/g,'0') })
Reference
Without replace/regex:
var foo = function (str) {
var result = "", char, i, l;
for (i = 0, l = str.length; i < l; i++) {
char = str[i];
if (char == '.') {
break;
} else if (char == '_') {
result += '0';
} else {
result += str[i];
}
char = str[i];
}
return result + str.slice(i);
}
With regex: dystroy
Benchmark for the various answers in this post:
http://jsperf.com/regex-vs-no-regex-replace
Unless you have some other obscure condition -
find:
_(?=[\d_.])
replace:
0
Or "To find also _ followed by nothing, example: 0__ or 2323.43_"
_(?=[\d_.]|$)
You could use lookahead assertion in regex...
"__3_23._45_4".replace(/_(?![^.]*$)/g,'0')
Result: 003023._45_4
Explanation:
/ # start regex
_ # match `_`
(?! # negative lookahead assertion
[^.]*$ # zero or more (`*`) not dots (`[^.]`) followed by the end of the string
) # end negative lookahead assertion
/g # end regex with global flag set
var str = "___345_345.4w3__w45.234__34_";
var dot = false;
str.replace(/[._]/g, function(a){
if(a=='.' || dot){
dot = true;
return a
} else {
return 0
}
})

Categories

Resources