Extracting decimal number upto two precision using regex in Javascript [duplicate] - javascript

I need some regex that will match only numbers that are decimal to two places. For example:
123 = No match
12.123 = No match
12.34 = Match

^[0-9]*\.[0-9]{2}$ or ^[0-9]*\.[0-9][0-9]$

var regexp = /^[0-9]*(\.[0-9]{0,2})?$/;
//returns true
regexp.test('10.50')
//returns false
regexp.test('-120')
//returns true
regexp.test('120.35')
//returns true
regexp.test('120')

If you're looking for an entire line match I'd go with Paul's answer.
If you're looking to match a number witihn a line try: \d+\.\d\d(?!\d)
\d+ One of more digits (same as [0-9])
\. Matches to period character
\d\d Matches the two decimal places
(?!\d) Is a negative lookahead that ensure the next character is not a digit.

It depends a bit on what shouldn't match and what should and in what context
for example should the text you test against only hold the number? in that case you could do this:
/^[0-9]+\.[0-9]{2}$/
but that will test the entire string and thus fail if the match should be done as part of a greater whole
if it needs to be inside a longer styring you could do
/[0-9]+\.[0-9]{2}[^0-9]/
but that will fail if the string is is only the number (since it will require a none-digit to follow the number)
if you need to be able to cover both cases you could use the following:
/^[0-9]+\.[0-9]{2}$|[0-9]+\.[0-9]{2}[^0-9]/

You can also try Regular Expression
^\d+(\.\d{1,2})?$
or
var regexp = /^\d+\.\d{0,2}$/;
// returns true
regexp.test('10.5')
or
[0-9]{2}.[0-9]{2}
or
^[0-9]\d{0,9}(\.\d{1,3})?%?$
or
^\d{1,3}(\.\d{0,2})?$

Related

regex lookahead confusion [duplicate]

I want a regex which returns true when there is at least 5 characters et 2 digits. For that, I use a the lookahead (i. e. (?=...)).
// this one works
let pwRegex = /(?=.{5,})(?=\D*\d{2})/;
let result = pwRegex.test("bana12");
console.log("result", result) // true
// this one won't
pwRegex = /(?=.{5,})(?=\d{2})/;
result = pwRegex.test("bana12");
console.log("result", result) // false
Why we need to add \D* to make it work ?
For me, \d{2} is looser than \D*\d{2} so it should not allow an acceptance of the test?
Your lookaheads only test from the current match position. Since you don't match anything, this means from the start. Since bana12 doesn't start with two digits, \d{2} fails. Its as simple as that ;)
Also, note that having \d{2} means your digits has to be adjacent. Is that your intention?
To simply require 2 digits, that doesn't need to be adjacent, try
/(?=.{5,})(?=\D*\d\D*\d)/
Note that lookaheads are zero-width assertions and when their patterns are matched the regex index stays at the same place where it has been before. The lookaheads in the patterns above are executed at the same locations.
The /(?=.{5,})(?=\d{2})/ pattern will match a location that has any 5 chars other than line break chars immediately to the right of the current location and the first 2 chars in this 5 char substring are digits.
You need to add \D* to let other types of chars before the 2 digits.
See more about that behavior at Lookarounds Stand their Ground.

Split a String by a Regex in JavaScript

I have the string:
"Vl.55.16b25.3d.42b50.59b30.90.24b35.3d.56.67b70.Tv.54b30.Vl.41b35.Tv.Bd.71b50.3d.99b20.03b50.Tv.73b50.Vl.05b25.12b40.Bd.Tv.82b25."
How to detached get results like:
["Vl.55.16b25", 3d.42.b50.59b30.90.24b35, 3d.56.67b70, ...]
The logic:
Condition 1: The End will be start b and 2 number. Example: b20, b25.
If pass condition 1 I need to check condition 2.
Condition 2: maybe like "3d" or 2 characters. If don't match condition 2 we need to pass the next character to the current block.
Many thanks.
If I understand your question correctly, the following code should work:
var string = "Vl.55.16b25.3d.42b50.59b30.90.24b35.3d.56.67b70.Tv.54b30.Vl.41b35.Tv.Bd.71b50.3d.99b20.03b50.Tv.73b50.Vl.05b25.12b40.Bd.Tv.82b25.";
console.log(string.split(/(?<=b\d\d)\.(?=3d)/g))
Explanation:
(?<=) is look-behind.
b matches the literal character "b".
\d matches any digit so \d\d will match two digits in a row.
\. matches a literal ".", it needs the \ before it because otherwise it would match any character.
(?=) is look-ahead.
The g flag stands for global so the string will be split up at every occurrence of the regular expression.
This means that the string will be split at every occurrence of "." that is preceded the letter "b" then two digits, and followed by "3d".
Assuming you want to separate by last having 'b' and two digits followed by 3d, two digits or the end of string (this is necessary) and by omitting leading dot, you could take the following regular expression.
const
string = "Vl.55.16b25.3d.42b50.59b30.90.24b35.3d.56.67b70.Tv.54b30.Vl.41b35.Tv.Bd.71b50.3d.99b20.03b50.Tv.73b50.Vl.05b25.12b40.Bd.Tv.82b25.",
result = string.match(/[^.].*?b\d\d(?=\.(3d|\D\D|$))/g);
console.log(result);

Regex replace not removing characters properly

I have the regular expression:
const regex = /^\d*\.?\d{0,2}$/
and its inverse (I believe) of
const inverse = /^(?!\d*\.?\d{0,2}$)/
The first regex is validating the string fits any positive number, allowing a decimal and two decimal digits (e.g. 150, 14., 7.4, 12.68). The second regex is the inverse of the first, and doing some testing I'm fairly confident it's giving the expected result, as it only validates when the string is anything but a number that may have a decimal and two digits after (e.g. 12..05, a5, 54.357).
My goal is to remove any characters from the string that do not fit the first regex. I thought I could do that this way:
let myString = '123M.45';
let fixed = myString.replace(inverse, '');
But this does not work as intended. To debug, I tried having the replace character changed to something I would be able to see:
let fixed = myString.replace(inverse, 'ZZZ');
When I do this, fixed becomes: ZZZ123M.45
Any help would be greatly appreciated.
I think I understand your logic here trying to find a regex that is the inverse of the regex that matches your valid string, in the hopes that it will allow you to remove any characters that make your string invalid and leave only the valid string. However, I don't think replace() will allow you to solve your problem in this way. From the MDN docs:
The replace() method returns a new string with some or all matches of a pattern replaced by a replacement.
In your inverse pattern you are using a negative lookahead. If we take a simple example of X(?!Y) we can think of this as "match X if not followed by Y". In your pattern your "X" is ^ and your "Y" is \d*\.?\d{0,2}$. From my understanding, the reason you are getting ZZZ123M.45 is that it is finding the first ^ (i.e, the start of the string) that is not followed by your pattern \d*\.?\d{0,2}$, and since 123M.45 doesn't match your "Y" pattern, your negative lookahead is satisfied and the beginning of your string is matched and "replaced" with ZZZ.
That (I think) is an explanation of what you are seeing.
I would propose an alternative solution to your problem that better fits with how I understand the .replace() method. Instead of your inverse pattern, try this one:
const invalidChars = /[^\d\.]|\.(?=\.)|(?<=\.\d\d)\d*/g
const myString = '123M..456444';
const fixed = myString.replace(invalidChars, '');
Here I am using a pattern that I think will match the individual characters that you want to remove. Let's break down what this one is doing:
[^\d\.]: match characters that are not digits
\.(?=\.): match . character if it is followed by another . character.
(?<=\.\d\d)\d*: match digits that are preceded by a decimal and 2 digits
Then I join all these with ORs (|) so it will match any one of the above patterns, and I use the g flag so that it will replace all the matches, not just the first one.
I am not sure if this will cover all your use cases, but I thought I would give it a shot. Here's a link to a breakdown that might be more helpful than mine, and you can use this tool to tweak the pattern if necessary.
I don't think you can do this
remove any characters from the string that do not fit the first regex
Because regex matching is meant for the entire string, and replace is used to replace just a PART inside that string. So the Regex inside replace must be a Regex to match unwanted characters only, not inverted Regex.
What you could do is to validate the string with your original regex, then if it's not valid, replace and validate again.
//if (notValid), replace unwanted character
// replace everything that's not a dot or digit
const replaceRegex = /[^\d.]/g; // notice g flag here to match every occurrence
const myString = '123M.45';
const fixed = myString.replace(replaceRegex, '');
console.log(fixed)
// validate again

How does the following code mean two consecutive numbers?

This is from an exercise on FCC beta and i can not understand how the following code means two consecutive numbers seeing how \D* means NOT 0 or more numbers and \d means number, so how does this accumulate to two numbers in a regexp?
let checkPass = /(?=\w{5,})(?=\D*\d)/;
This does not match two numbers. It doesn't really match anything except an empty string, as there is nothing preceding the lookup.
If you want to match two digits, you can do something like this:
(\d)(\d)
Or if you really want to do a positive lookup with the (?=\D*\d) section, you will have to do something like this:
\d(?=\D*\d)
This will match against the last digit which is followed by a bunch of non-digits and a single digit. A few examples (matched numbers highlighted):
2 hhebuehi3
^
245673
^^^^^
2v jugn45
^ ^
To also capture the second digit, you will have to put brackets around both numbers. Ie:
(\d)(?=\D*(\d))
Here it is in action.
In order to do what your original example wants, ie:
number
5+ \w characters
a non-number character
a number
... you will need to precede your original example with a \d character. This means that your lookups will actually match something which isn't just an empty string:
\d(?=\w{5,})(?=\D*\d)
IMPORTANT EDIT
After playing around a bit more with a JavaScript online console, I have worked out the problem with your original Regex.
This matches a string with 5 or more characters, including at least 1 number. This can match two numbers, but it can also match 1 number, 3 numbers, 12 numbers, etc. In order to match exactly two numbers in a string of 5-or-more characters, you should specify the number of digits you want in the second half of your lookup:
let regex = /(?=\w{5,})(?=\D*\d{2})/;
let string1 = "abcd2";
let regex1 = /(?=\w{5,})(?=\D*\d)/;
console.log("string 1 & regex 1: " + regex1.test(string1));
let regex2 = /(?=\w{5,})(?=\D*\d{2})/;
console.log("string 1 & regex 2: " + regex2.test(string1));
let string2 = "abcd23";
console.log("string 2 & regex 2: " + regex2.test(string2));
My original answer was about Regex in a vacuum and I glossed over the fact that you were using Regex in conjunction with JavaScript, which works a little differently when comparing Regex to a string. I still don't know why your original answer was supposed to match two numbers, but I hope this is a bit more helpful.
?= Positive lookahead
w{5,} matches any word character (equal to [a-zA-Z0-9_])
{5,}. matches between 5 and unlimited
\D* matches any character that\'s not a digit (equal to [^0-9])
* matches between zero and unlimited
\d matches a digit (equal to [0-9])
This expression is global - so tries to match all
You can always check your expression using regex101

Find number that follows certain string which includes both letters and punctuation

I am trying to find a way to extract the numbers that occur after abc/ immediately succeeding the / and before any further letters, numbers or punctuation.
E.g:
abc/134567/something should return 1234567
abc/1234567?foo=bar should still only return 1234567
blah/1234/abc/678 should only return 678 as I'm looking only for the number that succeeds abc/
I'm aware there are two options: regex or substring match.
In order to perform the substring match I need the index point but I'm dubious about merely doing an indexOf("abc/") as it only returns the index of the first letter - a - which could be present elsewhere in the string.
With regex I have struggled as I find that searching for a mixture of the letters and the slashes seems to cause it to return null.
So what's the best way?
You can use this regexpression :
var rgx = new RegExp("abc\/([0-9]+)","gi");
Then :
var m = rgx.exec("abc/1234567?foo=bar");
console.log(m[0]);
edited after comments
You could use a regular expression and seach for abc/ and following digits.
var array = ['abc/134567/something', 'abc/1234567?foo=bar', 'blah/1234/abc/678'];
console.log(array.map(s => s.match(/abc\/(\d+)/)[1]));
We accept string that has abc/, after it an integer number, that is taken as a matched group and either the end of string or some non-digit symbol after it.
abc\/(\d+)(?:$|\D)
test
You'll use in Javascript for matched group extraction:
var myRegexp = /abc\/(\d+)(?:$|\D)/g;
var match = myRegexp.exec(inputString);
var result=match[1]; // the number after abc/
In another regex engine than that of JavaScript, lookahead and lookbehind could be used. But in JS lookbehinds are forbidden. :-(. So we have to use this, a bit more complicated, way.
Are you after something like this:
^(.*\/)(\d+)(.*)
Where the second group will give you the digits after the slash.
Look at the regex here

Categories