match pattern nth digit of a number using regex - javascript

I am using a regex /^(\+88)?01[3-9]\d{8}$/
let phoneNum = "+880136486336"
let validRegex = /^(\+88)?01[3-9]\d{8}$/;
console.log(validRegex.test(phoneNum));
to match a pattern that matches some strings like
+8801712345678
01712345678
01312349876
It works fine but I also want to match 01[n] where n will be 3-9. pattern to find out the mobile network operator.
I want to do something like this
if the number is 01712345678 then print "Network Operator A",
if the number is +8801712345678 then print "Network Operator A"
if the number is 01312349678 then print "Network Operator B"
and different operators for different values of n.
here 017, 013, 014, 016, 015, 019, 018 are mobile operator codes which I want to use to find out operator based on the mobile number.
I don't find any way to do it.
How can I do it with regex?

You can capture the three digits at the start with a capturing group, then use String#match or RegExp#exec to get the actual match and then, if there is a match, get the group value and obtain the operator name from a dictionary:
const phones = ['+8801712345678','01712345678','01312349876'];
const operators = {'017' : 'Operator A', '013' : 'Operator C', '014' : 'Operator B', '016' : 'Operator D', '015' : 'Operator E', '019' : 'Operator F', '018' : 'Operator G'};
const validRegex = /^(?:\+88)?(01[3-9])\d{8}$/;
for (const phone of phones) {
const match = validRegex.exec(phone);
if (match) {
console.log(phone, "=> Valid, belongs to", operators[match[1]])
} else {
console.log(phone,"=> NO MATCH");
}
}
Here,
^(?:\+88)?(01[3-9])\d{8}$: the first optional group is now non-capturing and there is a capturing group with ID = 1 now, (01[3-9])
validRegex.exec(phone) gets the match object
operators[match[1]] returns the Operator name by the key.

Related

Get multiple regex match result all in one match by Javascript

I am trying to make my code looks professional by removing those duplicate code. the question is I want to get some data from a string, to be specific, I need to know the NUMBER, X, Y, Z, A, B, etc. values but the regex expression are different for each variable so I have to repeat myself writing a lot of duplicate code.
let TextString = `DRILL(NUMBER:=20,NAME:='4',PN:=1,X:=10.1,Y:=73.344,Z:=0,A:=-1.435,B:=1.045,M1:=1,M2:=2,M3:=3,M4:=4,M5:=1,S1:=10.5,S2:=2.1,S3:=1.2,S4:=2,S5:=2.4,RS1:=1,RS2:=2);`;
const regNumber = /(?<=NUMBER:=)[0-9]+/gm;
let lineNumber = Number(TextString.match(regNumber));
const regX = /(?<=X:=)(-?[0-9]+)(.[0-9]+)?/gm;
let X = Number(TextString.match(regX)).toFixed(1);
const regY = /(?<=Y:=)(-?[0-9]+)(.[0-9]+)?/gm;
let Y = Number(TextString.match(regY)).toFixed(1);
const regZ = /(?<=Z:=)(-?[0-9]+)(.[0-9]+)?/gm;
let Z = Number(TextString.match(regZ)).toFixed(1);
const regA = /(?<=A:=)(-?[0-9]+)(.[0-9]+)?/gm;
let A = Number(TextString.match(regA)).toFixed(1);
const regB = /(?<=B:=)(-?[0-9]+)(.[0-9]+)?/gm;
let B = Number(TextString.match(regB)).toFixed(1);
// and many more duplicate code.
console.log(lineNumber, X, Y, Z, A, B);
I could only think of a way like the above, to match each variable individually and run .match() multiple times, but as you can see there are 17 variables total and in real situations, there are hundreds of these TextString. I was worried that this matching process will have a huge impact on performance.
Are there any other ways to fetch all variables in one match and store them in an array or object? or any other elegant way of doing this?
Every coordinate will have a single letter identifier, so you can use a more general positive lookback (?<=,[A-Z]:=). This lookback matches a comma followed by a single uppercase letter then the equality symbol.
You can then use .match() to get all matches and use .map() to run the conversion you were doing.
let TextString = `DRILL(NUMBER:=20,NAME:='4',PN:=1,X:=10.1,Y:=73.344,Z:=0,A:=-1.435,B:=1.045,M1:=1,M2:=2,M3:=3,M4:=4,M5:=1,S1:=10.5,S2:=2.1,S3:=1.2,S4:=2,S5:=2.4,RS1:=1,RS2:=2);`;
const regNumber = /(?<=NUMBER:=)[0-9]+/gm;
let lineNumber = Number(TextString.match(regNumber));
const regex = /(?<=,[A-Z]:=)(-?[0-9]+)(.[0-9]+)?/gm;
let coord = TextString.match(regex).map(n => Number(n).toFixed(1));
console.log(lineNumber, coord);
You could write a single pattern:
(?<=\b(?:NUMBER|[XYZAB]):=)-?\d+(?:\.\d+)?\b
Explanation
(?<= Positive lookbehind, assert that to the left of the current position is
\b(?:NUMBER|[XYZAB]):= Match either NUMBER or one of X Y Z A B preceded by a word boundary and followed by :=
) Close the lookbehind
-? Match an optional -
\d+(?:\.\d+)? Match 1+ digits and an optional decimal part
\b A word boundary to prevent a partial word match
See a regex demo.
const TextString = `DRILL(NUMBER:=20,NAME:='4',PN:=1,X:=10.1,Y:=73.344,Z:=0,A:=-1.435,B:=1.045,M1:=1,M2:=2,M3:=3,M4:=4,M5:=1,S1:=10.5,S2:=2.1,S3:=1.2,S4:=2,S5:=2.4,RS1:=1,RS2:=2);`;
const regNumber = /(?<=\b(?:NUMBER|[XYZAB]):=)-?\d+(?:\.\d+)?\b/g;
const result = TextString
.match(regNumber)
.map(s =>
Number(s).toFixed(1)
);
console.log(result);
One possible approach could be based on a regex pattern which utilizes capturing groups. The matching regex for the OP's sample text would look like this ...
/\b(NUMBER|[XYZAB])\:=([^,]+),/g
... and the description is provided with the regex' test site.
The pattern is both simple and generic. The latter is due to always capturing both the matching key like Number and its related value like 20. Thus it doesn't matter where a key-value pair occurs within a drill-data string.
Making use later of an object based Destructuring Assignment for assigning all of the OP's variables at once the post processing task needs to reduce the result array of matchAll into an object which features all the captured keys and values. Within this task one also can control how the values are computed and/or whether or how the keys might get sanitized.
const regXDrillData = /\b(NUMBER|[XYZAB])\:=([^,]+),/g;
const textString =
`DRILL(NUMBER:=20,NAME:='4',PN:=1,X:=10.1,Y:=73.344,Z:=0,A:=-1.435,B:=1.045,M1:=1,M2:=2,M3:=3,M4:=4,M5:=1,S1:=10.5,S2:=2.1,S3:=1.2,S4:=2,S5:=2.4,RS1:=1,RS2:=2);`;
// - processed values via reducing the captured
// groups of a `matchAll` result array of a
// generic drill-data match-pattern.
const {
number: lineNumber,
x, y, z,
a, b,
} = [...textString.matchAll(regXDrillData)]
.reduce((result, [match, key, value]) => {
value = Number(value);
value = (key !== 'NUMBER') ? value.toFixed(1) : value;
return Object.assign(result, { [ key.toLowerCase() ]: value });
}, {})
console.log(
`processed values via reducing the captured
groups of a 'matchAll' result array of a
generic drill-data match-pattern ...`,
{ lineNumber, x, y, z, a, b },
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
Every value match a pattern :=[value], or :=[value]) for the last one. So there is my regex
(?<=:=)-?[\d\w.']+(?=[,)])
Positive Lookbehind (?<=:=) look for match behind :=
-? match - optional (for negative number)
[\d\w.']+: match digit, word character, ., '
Positive Lookahead (?=[,)]) look for match ahead character , or )
Live regex101.com demo
Now change your code to
let TextString = `DRILL(NUMBER:=20,NAME:='4',PN:=1,X:=10.1,Y:=73.344,Z:=0,A:=-1.435,B:=1.045,M1:=1,M2:=2,M3:=3,M4:=4,M5:=1,S1:=10.5,S2:=2.1,S3:=1.2,S4:=2,S5:=2.4,RS1:=1,RS2:=2);`;
const regexPattern= /(?<=:=)-?[\d\w.']+(?=[,)])/g;
console.log(TextString.match(regexPattern))
// ['20', "'4'", '1', '10.1', '73.344', '0', '-1.435', '1.045', '1', '2', '3', '4', '1', '10.5', '2.1', '1.2', '2', '2.4', '1', '2']
Edit
I just realized the the Positive Lookahead is unnecessary as #Peter Seliger
mentioned
(?<=:=)-?[\d\w.']+
Change your regex pattern to
const regexPattern= /(?<=:=)-?[\d\w.']+/g;
Here is a solution using a .reduce() on keys of interest and returns an object:
const TextString = `DRILL(NUMBER:=20,NAME:='4',PN:=1,X:=10.1,Y:=73.344,Z:=0,A:=-1.435,B:=1.045,M1:=1,M2:=2,M3:=3,M4:=4,M5:=1,S1:=10.5,S2:=2.1,S3:=1.2,S4:=2,S5:=2.4,RS1:=1,RS2:=2);`;
const keys = [ 'NUMBER', 'X', 'Y', 'Z', 'A', 'B' ];
let result = keys.reduce((obj, key) => {
const regex = new RegExp('(?<=\\b' + key + ':=)-?[0-9.]+');
obj[key] = Number(TextString.match(regex)).toFixed(1);
return obj;
}, {});
console.log(result);
Output:
{
"NUMBER": "20.0",
"X": "10.1",
"Y": "73.3",
"Z": "0.0",
"A": "-1.4",
"B": "1.0"
}
Notes:
The regex is built dynamically from the key
A \b word boundary is added to the regex to reduce the chance of unintended matches
If you need the line number as an integer you could take that out of the keys, and handle it separately.

How to change given string to regex modified string using javascript

Example strings :
2222
333333
12345
111
123456789
12345678
Expected result:
2#222
333#333
12#345
111
123#456#789
12#345#678
i.e. '#' should be inserted at the 4th,8th,12th etc last position from the end of the string.
I believe this can be done using replace and some other methods in JavaScript.
for validation of output string i have made the regex :
^(\d{1,3})(\.\d{3})*?$
You can use this regular expression:
/(\d)(\d{3})$/
this will match and group the first digit \d and group the last three \d{3} which are then grouped in their own group. Using the matched groups, you can then reference them in your replacement string using $1 and $2.
See example below:
const transform = str => str.replace(/(\d)(\d{3})$/, '$1#$2');
console.log(transform("2222")); // 2#222
console.log(transform("333333")); // 333#333
console.log(transform("12345")); // 12#345
console.log(transform("111")); // 111
For larger strings of size N, you could use other methods such as .match() and reverse the string like so:
const reverse = str => Array.from(str).reverse().join('');
const transform = str => {
return reverse(reverse(str).match(/(\d{1,3})/g).join('#'));
}
console.log(transform("2222")); // 2#222
console.log(transform("333333")); // 333#333
console.log(transform("12345")); // 12#345
console.log(transform("111")); // 111
console.log(transform("123456789")); // 123#456#789
console.log(transform("12345678")); // 12#345#678
var test = [
'111',
'2222',
'333333',
'12345',
'123456789',
'1234567890123456'
];
console.log(test.map(function (a) {
return a.replace(/(?=(?:\B\d{3})+$)/g, '#');
}));
You could match all the digits. In the replacement insert an # after every third digit from the right using a positive lookahead.
(?=(?:\B\d{3})+$)
(?= Positive lookahead, what is on the right is
(?:\B\d{3})+ Repeat 1+ times not a word boundary and 3 digits
$ Assert end of string
) Close lookahead
Regex demo
const regex = /^\d+$/;
["2222",
"333333",
"12345",
"111",
"123456789",
"12345678"
].forEach(s => console.log(
s.replace(/(?=(?:\B\d{3})+$)/g, "#")
));

Regex match everything after match set except for match set

This may be a simple expression to write but I am having the hardest time with this one. I need to match group sets where each group has 2 parts, what we can call the operation and the value. I need the value to match to anything after the operation EXCEPT another operation.
Valid operations to match (standard math operators): [>,<,=,!,....]
For example: '>=25!30<50' Would result in three matching groups:
1. (>=, 25)
2. (!, 30)
3. (<, 50)
I can currently solve the above using: /(>=|<=|>|<|!|=)(\d*)/g however this only works if the characters in the second match set are numbers.
The wall I am running into is how to match EVERYTHING after EXCEPT for the specified operators.
For example I don't know how to solve: '<=2017-01-01' without writing a regex to specify each and every character I would allow (which is anything except the operators) and that just doesn't seem like the correct solution.
There has got to be a way to do this! Thanks guys.
What you might do is match the operations (>=|<=|>|<|!|=) which will be the first of the 2 parts and in a capturing group use a negative lookahead to match while there is not an operation directly at the right side which will be the second of the 2 parts.
(?:>=|<=|>|<|!|=)((?:(?!(?:>=|<=|>|<|!|=)).)+)
(?:>=|<=|>|<|!|=) Match one of the operations using an alternation
( Start capturing group (This will contain your value)
(?: Start non capturing group
(?!(?:>=|<=|>|<|!|=)). Negative lookahead which asserts what is on the right side is not an operation and matches any character .
)+ Close non capturing group and repeat one or more times
) Close capturing group
const regex = /(?:>=|<=|>|<|!|=)((?:(?!(?:>=|<=|>|<|!|=)).)+)/gm;
const strings = [
">=25!30<50",
">=test!30<$##%",
"34"
];
let m;
strings.forEach((s) => {
while ((m = regex.exec(s)) !== null) {
if (m.index === regex.lastIndex) {
regex.lastIndex++;
}
console.log(m[1]);
}
});
You can use this code
var str = ">=25!30<50";
var pattern = RegExp(/(?:([\<\>\=\!]{1,2})(\d+))/, "g");
var output = [];
let matchs = null;
while((matchs = pattern.exec(str)) != null) {
output.push([matchs[1], matchs[2]]);
}
console.log(output);
Output array :
0: Array [ ">=", "25" ]
​
1: Array [ "!", "30" ]
​
2: Array [ "<", "50" ]
I think this is what you need:
/((?:>=|<=|>|<|!|=)[^>=<!]+)/g
the ^ excludes characters you don't want, + means any number of

Javascript regex that matches one pattern in string but exclude another

I have two possible strings that I need to match:
+/-90000
and
+9000 / -80000
I need to recognise the two patterns separately so wrote some regex for this. The first single number string I can match like so:
/\+\/\-{1}/g
And i wrote this for the second:
/(\+(?=[0-9]+){1}|\-(?=[0-9]+){1}|\/(?=\s){1})/g
The second would also partially match the first the first number i.e. the -90000. Is there a way that they can be improved so that they match exclusively?
You can use a single expression:
^(?:(\+\/-\s*\d+)|((\+\s*\d+)\s*\/\s*(-\s*\d+)))$
The only restriction you'll have to work with would be that in the second type of input, the positive number should come first.
You'll get the matched group in matches[1] if the input was of type 1, and in matches[2] if it was of type 2. For the type-2 input, further matches of each number gets stored in matches[3] and matches[4].
You can see the demo on regex101.
Here are two solutions with slightly different semantics.
With the first, if the string is type 1 the number will be in capture group 1 (result[1]) and if it's type 2 the numbers will be in capture groups 2 and 3 (and capture group 1 will be null). The test for type 1, then, is result[1] !== null.
var a = '+/-90000';
var b = '+9000 / -80000';
var result;
var expr1 = /\+(?:\/-(\d+)|(\d+) \/ -(\d+))/;
result = a.match(expr1);
// => [ '+/-90000', '90000', null, null ]
result = b.match(expr1);
// => [ '+9000 / -80000', null, '9000', '80000' ]
With the second, if the string is type 1 the number will be in capture group 1 (and capture group 2 will be null), and if it's type 2 the numbers will be in capture groups 2 and 3. The test for type 1 is result[1] === null.
var expr2 = /\+(\d+ )?\/ ?-(\d+)/;
result = a.match(expr2);
// => [ '+/-90000', null, '90000' ]
result = b.match(expr2);
// => [ '+9000 / -80000', '9000', '80000' ]

Regex - match any digit in a string

I have the following Javascript
function myFunction() {
var str = "depth10 shown";
var depth= str.match(/^depth[\d+$]/);
console.log(depth);
}
My function is trying to find if depth* is present in the string, where * is always numeric (ex: depth0, depth1, depth100) and return the numeric value in it. In the example above, depth is always returning only one digit instead of all digits. Can anyone explain why?
You're improperly utilizing a character class, you want to use a capturing group instead:
var str = 'depth10 shown or depth100 and depth1'
var re = /depth(\d+)/gi,
matches = [];
while (m = re.exec(str)) {
matches.push(m[1]);
}
console.log(matches) //=> [ '10', '100', '1' ]
Note: If you will have more than 1 "depth*" substrings in your string, you'll want to use the exec() method in a loop pushing the match result of the captured group to the results array.
Otherwise, you can use the match method here:
var r = 'depth10 shown'.match(/depth(\d+)/)
if (r)
console.log(r[1]); //=> "10"
$ Matches end of input. ie. /t$/ does not match the 't' in "eater", but does match it in "eat".
^ Matches beginning of input. ie, /^A/ does not match the 'A' in "an A", but does match the 'A' in "An E".
Try:
var str = "depth10 shown".match(/depth\d+/gi);
console.log(str[0])

Categories