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
Related
I'm struggling with finding the correct RegExp to match number with plus (+) or minus (-) sign at the end.
I have a select list of number ranging from 0.00- to 40.00- and 0.00+ to 40.00-. I'm using the following RegExp to filter out non matching records:
$("#MySelectBox").change(function() {
var filter = $(this).val()
// If the list item does not contain the numbers phrase fade it out
if ($(this).text().search(new RegExp('\\b'+filter+'\\b', "i")) < 0) {
$(this).hide();
} else {
$(this).show();
}
However, it will show both + and - numbers. For example: if filter = 3.00+ then it will return both 3.00+ and 3.00- values.
Any ideas how to get the exact match?
[\+-]\d{1,2}\.00
Will match + or -, followed by one or two digits (\d{1,2}), followed by .00.
However, RegExes don't have "greater than 40" kind of logic. They only match patterns.
There are useful tools to help you, like Rexegpal
So with your brief:
Check string matches pattern: "+xx.xx" or "-xx.xx"
Only numbers between -40 or +40
Omit results out of bounds
This could be a good way to achieve your desired result.
Notes: (1) Unsure if you wanted to enforce the demical point, (2) there are certainly multiple ways to achieve your result, this is is just one.
const regex = /^[\-\+]\d+\.*\d*$/;
const tests = ["41", "20", "+20", "-20", "+20.00", "-20.20", "20.20"];
const passedTests = tests.filter(number => {
const parsedNumber = Number.parseFloat(number);
const isValid = !!number.match(regex) && parsedNumber > -40 && parsedNumber < 40;
console.log(`Test ${number}, result: ${isValid}`);
return isValid;
});
console.log(passedTests);
To get an exact match for a number with plus (+) or minus (-) sign at the end and from 0.00- to 40.00- and 0.00+ to 40.00+, you can use:
^(?:(?:[0-9]|[123]\d)\.\d\d|40\.00)[+-]$
^ Start of string
(?: Non capture group for the alternation |
(?:[0-9]|[123]\d) Match either a digit 0-9 or a number 10 - 39
\.\d\d Match a . and 2 digits 0-9
| Or
40\.00 Match 40.00
) Close group
[+-] Match either + or -
$ End of string
Regex demo
In Javascript you can use
const regex = /^(?:(?:[0-9]|[123]\d)\.\d\d|40\.00)[+-]$/;
If the value is not the only value in the string, you could start with pattern with a word boundary \b and assert a whitespace boundary at the right (?!\S)
\b(?:(?:[0-9]|[123]\d)\.\d\d|40\.00)[+-](?!\S)
Regex demo
I need to parse a string that comes like this:
-38419-indices-foo-7119-attributes-10073-bar
Where there are numbers followed by one or more words all joined by dashes. I need to get this:
[
0 => '38419-indices-foo',
1 => '7119-attributes',
2 => '10073-bar',
]
I had thought of attempting to replace only the dash before a number with a : and then using .split(':') - how would I do this? I don't want to replace the other dashes.
Imo, the pattern is straight-forward:
\d+\D+
To even get rid of the trailing -, you could go for
(\d+\D+)(?:-|$)
Or
\d+(?:(?!-\d|$).)+
You can see it here:
var myString = "-38419-indices-foo-7119-attributes-10073-bar";
var myRegexp = /(\d+\D+)(?:-|$)/g;
var result = [];
match = myRegexp.exec(myString);
while (match != null) {
// matched text: match[0]
// match start: match.index
// capturing group n: match[n]
result.push(match[1]);
match = myRegexp.exec(myString);
}
console.log(result);
// alternative 2
let alternative_results = myString.match(/\d+(?:(?!-\d|$).)+/g);
console.log(alternative_results);
Or a demo on regex101.com.
Logic
lazy matching using quantifier .*?
Regex
.*?((\d+)\D*)(?!-)
https://regex101.com/r/WeTzF0/1
Test string
-38419-indices-foo-7119-attributes-10073-bar-333333-dfdfdfdf-dfdfdfdf-dfdfdfdfdfdf-123232323-dfsdfsfsdfdf
Matches
Further steps
You need to split from the matches and insert into your desired array.
How use regexp match all repeat substring in javascript?
For example:
Get [ "cd","cd","cdcd","cdcdcd", "cdcdcdcd" ] by "abccdddcdcdcdcd123"
+ is not working:
"abccdddcdcdcdcd123".match(/(cd)+/g)
Array [ "cd", "cdcdcdcd" ]
This can be done with positive look aheads ?=. This type of matching doesnt move the cursor forward so you can match the same content multiple times.
var re = /cd(?=((cd)*))/g;
var str = "abccdddcdcdcdcd123";
var m;
while (m = re.exec(str)) {
console.log(m[0]+m[1]);
}
Capture group 0 gets the first cd, then a positive lookahead captures all subsequent cd characters. You can combine the two to get the desired result.
See https://www.regular-expressions.info/refadv.html
Matches at a position where the pattern inside the lookahead can be matched. Matches only the position. It does not consume any characters or expand the match. In a pattern like one(?=two)three, both two and three have to match at the position where the match of one ends.
I guess you could also do it like this.
Put the capture group inside a lookahead assertion.
Most engines bump the current regex position if it didn't change since
last match. Not JS though, you have to do it manually via incrementing lastIndex.
Readable regex
(?=
( # (1 start)
(?: cd )+
) # (1 end)
)
var re = /(?=((?:cd)+))/g;
var str = "abccdddcdcdcdcd123";
var m;
while (m = re.exec(str)) {
console.log( m[1] );
++re.lastIndex;
}
I think the common solution to an overlapping match problem like this should be as following:
/(?=((cd)+))cd
Match the inner pattern in group one or more times in a lookahead whilst moving the carret two characters at a time ahead. (We could also move by two dots ..).
Code sample:
var re = /(?=((cd)+))cd/g;
var str = "abccdddcdcdcdcd123";
var m; //var arr = new Array();
while (m = re.exec(str)) {
//arr.push(m[1]);
console.log(m[1]);
}
We get the result from group 1 via m[1].
Use .push(m[1]); to add it to an array.
Good day,
I am trying to return groups of 3 digits of a given string where digits are "consumed" twice in JavaScript:
From a string "123 456" I would like exec to return ["1", "12"] for the first match, ["2", "23"] and so on.
I tried using a lookahead like this:
let exp = /(\d(?=\d\d))/g;
let match;
while(match = exp.exec("1234 454")) {
console.log(match);
}
This, will however still only each digit which precedes two digits.
Does someone have a solution? I have searched but am not exactly sure what to search for so I might have missed something.
Thank you in advance!
You need to capture inside a positive lookahead here:
let exp = /(?=((\d)\d))/g;
let match;
while(match = exp.exec("1234 454")) {
if (match.index === exp.lastIndex) { // \
exp.lastIndex++; // - Prevent infinite loop
} // /
console.log([match[1], match[2]]); // Print the output
}
The (?=((\d)\d)) pattern matches a location followed with 2 digits (captured into Group 1) the first being captured into Group 2.
I want to capture the "1" and "2" in "http://test.com/1/2". Here is my regexp /(?:\/([0-9]+))/g.
The problem is that I only get ["/1", "/2"]. According to http://regex101.com/r/uC2bW5 I have to get "1" and "1".
I'm running my RegExp in JS.
You have a couple of options:
Use a while loop over RegExp.prototype.exec:
var regex = /(?:\/([0-9]+))/g,
string = "http://test.com/1/2",
matches = [];
while (match = regex.exec(string)) {
matches.push(match[1]);
}
Use replace as suggested by elclanrs:
var regex = /(?:\/([0-9]+))/g,
string = "http://test.com/1/2",
matches = [];
string.replace(regex, function() {
matches.push(arguments[1]);
});
In Javascript your "match" has always an element with index 0, that contains the WHOLE pattern match. So in your case, this index 0 is /1 and /2 for the second match.
If you want to get your DEFINED first Matchgroup (the one that does not include the /), you'll find it inside the Match-Array Entry with index 1.
This index 0 cannot be removed and has nothing to do with the outer matching group you defined as non-matching by using ?:
Imagine Javascript wrapps your whole regex into an additional set of brackets.
I.e. the String Hello World and the Regex /Hell(o) World/ will result in :
[0 => Hello World, 1 => o]