regular expression to validate a pattern - javascript

I am new to regular expression, In my project i am allowing user to put amount in shorthand as well as full digit, i have used material UI TextField for input.
Examples are:
400k - shorthand,
400.2k - shorthand,
4m - shorthand,
500. - should work
500000 - full amount
some pattern user should not be allowed to enter example are:
4.2.k,
.3k,
4...k
300.k
I have written regex which is below but it does allows to enter dot after number.
textValue.match(/^[0-9]*(\.[0-9]{0,2})*([0-9km]{1})$/) && textValue.match(/^[\d]+/)
above code first regex validates the pattern and second regex forces user to put Number because amount cannot start with string, i have wrote two separate regex as i don't understand how to put them in one regex and those regex doesn't accepts dot after number. Please can anyone give a perfect Regex to validate the above pattern in one single regular expression??
Thanks in advance

With alternation (never really the prettiest) it could be done like:
^\d+([km]|\.|\.\d+[km])?$
See the Online Demo
^ - Start string ancor.
d+ - One or more digits.
( - Opening capturing group (you could use non-capturing).
[km] - A single character "k" or "m".
| - Alternation (OR).
\.? - A literal dot.
| - Alternation (OR).
\.\d+[km] - A literal dot followed by at least one digit and a character "k" or "m".
)? - Close capturing group and make it optional
$ - Start string ancor.

About the pattern you tried
Note that you don't need {1}. The character class [0-9km] matches 1 of a char k or m or a digit 0-9. This way the possible digits to match could be 0-3 instead of 0-2.
Using the quantifier * for the group makes it possbile to also match 400.25.22.22.22k
You could use this pattern to validate the examples. The [0-9]+ at the beginning of the pattern makes sure that there has to be at least a single digit present.
If you want to allow 500. you could use:
^[0-9]+(?:(?:\.[0-9]{1,2})?[km]?|\.)$
Explanation
^ Start of string
[0-9]+ Match 1+ digits
(?: Non capture group
(?:\.[0-9]{1,2})? Match an optional decimal part with 2 digits
[km]? Match optional k or m
| Or
\. Match a single dot
)$ End of string
Regex demo
let pattern = /^[0-9]+(?:(?:\.[0-9]{1,2})?[km]?|\.)$/;
[
"400k",
"400.2k",
"4m",
"500000",
"500.",
"300.k",
"4.2.k",
".3k",
"4...k",
].forEach(s => console.log(s + " --> " + pattern.test(s)));
Another option is to only match the dot when not directly followed by k or m
^[0-9]+(?:\.(?![km]))?\d*[km]?$
Regex

You can try:
^\d+\.?(?:\d+)?[KkMm]?(?<!\.[KkMm])$
Explanation of the above regex:
^, $ - Matches start and end of the line respectively.
\d+ - Matches digits 1 or more times.
\.? - Represents 0 or 1 occurrence of ..
[KkMm]? - Matches optional characters from the mentioned character class.
(?<!\.[KkMm]) - Represents a negative look-behind not matching a a character after ..
You can find the demo of the above regex in here.
const regex = /^\d+\.?(?:\d+)?[KkMm]?(?<!\.[KkMm])$/gm;
const str = `400K
4.2.K
4.3K
3.2M
300000
4....K
4K
500.
300.K`;
let m;
while ((m = regex.exec(str)) !== null) {
// The result can be accessed through the `m`-variable.
m.forEach((match, groupIndex) => {
console.log(`${match}`);
});
}
2nd efficient solution using alternation:
You can probably try this regex for more efficient implementation
^\d+(?:\.$|\.\d+)?[KkMm]?$
Explanation of the above regex:
^, $ - Matches start and end of the line respectively.
\d+ - Matches digits 1 or more times.
(?:\.$|\.\d+)? - Represents a non-capturing group; matching either numbers followed by only . or decimal numbers.
[KkMm]? - Matches one of the mentioned characters zero or 1 time.
You can find the demo of the above regex in here.
const regex = /^\d+(?:\.$|\.\d+)?[KkMm]?$/gm;
const str = `400K
4.2.K
4.3K
3.2M
300000
4....K
4K
500.
300.K`;
let m;
while ((m = regex.exec(str)) !== null) {
// The result can be accessed through the `m`-variable.
m.forEach((match, groupIndex) => {
console.log(`${match}`);
});
}

Related

Javascript Regular Expressions - Replace non-numeric characters

I have this line:
val = val.replace(/[^0-9\.]/g, '')
and it replaces anything that is not a number, but I need a regular expression that limits val to be 2 numbers, period and then 2 numbers, like this:
- 11.33
- 12.34
- 54.65
I've already tried something like this but it didn't work:
val = val.replace(/^[^0-9\.]{1,2}/g, '')
Normally with replace you scan the entire string and keep the middle part. So start with beginning (^), scan some stuff you don't care about (.), then scan your number ([0-9]{1,2}(?:.[0-9]{0-2})?), then scan the rest which you don't care about (.), then you're at the end ($).
Then you replace with the middle capture group.
val.replace(/^(.*)([0-9]{1,2}(?:\.[0-9]{0-2})?)(.*)$/gm,'\2');
Use the m flag to process line by line.
Sometimes it is easier to use multiple regexes instead of one. Here is a solution that uses a first regex to strip the string from anything but number digits, then a second regex that reduces the number string to the proper length:
const regex1 = /[^\d\.]/g;
const regex2 = /^.*(\d\d\.\d\d).*$/;
[
'aaa11.33zzz',
'aaa123.456zzz',
'-54.65',
'12xtra.34'
].forEach(str => {
let result = str.replace(regex1, '').replace(regex2, '$1');
console.log(str, '==>', result);
});
Output:
aaa11.33zzz ==> 11.33
aaa123.456zzz ==> 23.45
-54.65 ==> 54.65
12xtra.34 ==> 12.34
Explanation of regex1:
[^\d\.] -- anything not 0-9 and .
g -- flag to replace pattern multiple times
Explanation of regex2:
^ -- anchor at start of string
.* -- greedy scan
(\d\d\.\d\d) -- expect 2 digits, a dot, and 2 digits
.* -- greedy scan
$ -- anchor at end of string
You did not specify what should happen if the input string has less than the 2digits, dot, 2 digits pattern. So this solution does not address that case.

Regex contains only numbers with optional ||/&& and number

examples where the regex should return true: 1&&2, 1||2, 1&&2||3, 1
examples where the regex should return false: 1||, 1&&, &&2
My regex is:
[0-9]+([\\|\\|\\&&][0-9])*
but it returns true if the input is 1&&&2.
Where is my mistake?
Note that [\|\|\&&] matches a single | or & char, not || or && sequences of chars. Also, the [0-9] without a quantifier matches only one digit. Without anchors, you may match a string partially inside a longer string.
You may use
^[0-9]+(?:(?:\|\||&&)[0-9]+)*$
Actually, to match anywhere inside a string, keep on using the pattern without anchors:
[0-9]+(?:(?:\|\||&&)[0-9]+)*
See the regex demo
Details
^ - start of string
[0-9]+ - 1+ digits
(?:(?:\|\||&&)[0-9])* - 0 or more repetitions of
(?:\|\||&&) - || or && sequence of characters
[0-9]+ - 1+ digits
$ - end of string.
JS demo:
const reg = /^[0-9]+(?:(?:\|\||&&)[0-9]+)*$/;
console.log( reg.test('1||2') ); // => true

How to match string with hypens in JavaScript?

I want to match certain parts of a URL that has the following form:
http://example.com/somepath/this-is-composed-of-hypens-3144/someotherpath
More precisely, I want to match only the part that is composed of all hypens and ends in numbers. So, I want to extract the part this-is-composed-of-hypens-3144 in the above URL. I have something like this:
const re = /[a-z]*-[a-z]*-[0-9]*/gis;
const match = re.exec(url);
return (match && match.length) ? match[0] : null;
However, this works only if there are 2 hypens, however, the number of hypens in my case can be arbitrary. How can I make my regex work for arbitrary number of hypens?
You may use
/\/([a-z]+(?:-[a-z]+)*-[0-9]+)(?:\/|$)/i
See the regex demo
Details
\/ - a / char
([a-z]+(?:-[a-z]*)*-[0-9]+) - Capturing group 1:
[a-z]+ - 1+ ASCII letters
(?:-[a-z]+)* - 0+ occurrences of - followed with 1+ ASCII letters
(?:\/|$) - either / or end of string.
If there can be any word chars, not just ASCII letters, you may replace each [a-z] with \w.
var s = "http://example.com/somepath/this-is-composed-of-hypens-3144/someotherpath";
var m = s.match(/\/([a-z]+(?:-[a-z]+)*-[0-9]+)(?:\/|$)/i);
if (m) {
console.log(m[1]);
}

How do I enforce that certain characters must be present when there is an optional character before them?

I would like to capture a string that meets the criteria:
may be empty
if it is not empty it must have up to three digits (-> \d{1,3})
may be optionally followed by a uppercase letter ([A-Z]?)
may be optionally followed by a forward slash (i.e. /) (-> \/?); if it is followed by a forward slash it must have from one to three digits
(-> \d{1,3})
Here's a valid input:
35
35A
35A/44
Here's invalid input:
34/ (note the lack of a digit after '/')
I've come up with the following ^\d{0,3}[A-Z]{0,1}/?[1,3]?$ that satisfies conditions 1-3. How do I deal with 4 condition? My Regex fails at two occassions:
fails to match when there is a digit and a forward slash and a digit e.g .77A/7
matches but it shouldn't when there isa digit and a forward slash, e.g. 77/
You may use
/^(?:\d{1,3}[A-Z]?(?:\/\d{1,3})?)?$/
See the regex demo
Details
^ - start of string
(?:\d{1,3}[A-Z]?(?:\/\d{1,3})?)? - an optional non-capturing group:
\d{1,3} - one to three digits
[A-Z]? - an optional uppercase ASCII letter
(?:\/\d{1,3})? - an optional non-capturing group:
\/ - a / char
\d{1,3} - 1 to 3 digits
$ - end of string.
Visual graph (generated here):
This should work. You were matching an optional slash and then an optional digit from 1 to 3; this matches an optional combination of a slash and 1-3 of any digits. Also, your original regex could match 0 digits at the beginning; I believe that this was in error, so I fixed that.
var regex = /^(\d{1,3}[A-Z]{0,1}(\/\d{1,3})?)?$/g;
console.log("77A/7 - "+!!("77A/7").match(regex));
console.log("77/ - "+!!("77/").match(regex));
console.log("35 - "+!!("35").match(regex));
console.log("35A - "+!!("35A").match(regex));
console.log("35A/44 - "+!!("35A/44").match(regex));
console.log("35/44 - "+!!("35/44").match(regex));
console.log("34/ - "+!!("34/").match(regex));
console.log("A/3 - "+!!("A/3").match(regex));
console.log("[No string] - "+!!("").match(regex));

Regular expression capture with optional trailing underscore and number

I'm trying to find a regular expression that will match the base string without the optional trailing number (_123). e.g.:
lorem_ipsum_test1_123 -> capture lorem_ipsum_test1
lorem_ipsum_test2 -> capture lorem_ipsum_test2
I tried using the following expression, but it would only work when there is a trailing _number.
/(.+)(?>_[0-9]+)/
/(.+)(?>_[0-9]+)?/
Similarly, adding the ? (zero or more) quantifier only worked when there is no trailing _number, otherwise, the trailing _number would just be part of the first capture.
Any suggestions?
You may use the following expression:
^(?:[^_]+_)+(?!\d+$)[^_]+
^ Anchor beginning of string.
(?:[^_]+_)+ Repeated non capturing group. Negated character set for anything other than a _, followed by a _.
(?!\d+$) Negative lookahead for digits at the end of the string.
[^_]+ Negated character set for anything other than a _.
Regex demo here.
Please note that the \n in the character sets in the Regex demo are only for demonstration purposes, and should by all means be removed when using as a pattern in Javascript.
Javascript demo:
var myString = "lorem_ipsum_test1_123";
var myRegexp = /^(?:[^_]+_)+(?!\d+$)[^_]+/g;
var match = myRegexp.exec(myString);
console.log(match[0]);
var myString = "lorem_ipsum_test2"
var myRegexp = /^(?:[^_]+_)+(?!\d+$)[^_]+/g;
var match = myRegexp.exec(myString);
console.log(match[0]);
You might match any character and use a negative lookahead that asserts that what follows is not an underscore, one or more digits and the end of the string:
^(?:(?!_\d+$).)*
Explanation
^ Assert start of the string
(?: Non capturing group
(?! Negative lookahead to assert what is on the right side is not
_\d+$Match an underscore, one or more digits and assert end of the string
.) Match any character and close negative lookahead
)* Close non capturing group and repeat zero or more times
Regex demo
const strings = [
"lorem_ipsum_test1_123",
"lorem_ipsum_test2"
];
let pattern = /^(?:(?!_\d+$).)*/;
strings.forEach((s) => {
console.log(s + " ==> " + s.match(pattern)[0]);
});
You are asking for
/^(.*?)(?:_\d+)?$/
See the regex demo. The point here is that the first dot pattern must be non-greedy and the _\d+ should be wrapped with an optional non-capturing group and the whole pattern (especially the end) must be enclosed with anchors.
Details
^ - start of string
(.*?) - Capturing group 1: any zero or more chars other than line break chars, as few as possible due to the non-greedy ("lazy") quantifier *?
(?:_\d+)? - an optional non-capturing group matching 1 or 0 occurrences of _ and then 1+ digits
$ - end of string.
However, it seems easier to use a mere replacing approach,
s = s.replace(/_\d+$/, '')
If the string ends with _ and 1+ digits, the substring will get removed, else, the string will not change.
See this regex demo.
Try to check if the string contains the trailing number. If it does you get only the other part. Otherwise you get the whole string.
var str = "lorem_ipsum_test1_123"
if(/_[0-9]+$/.test(str)) {
console.log(str.match(/(.+)(?=_[0-9]+)/g))
} else {
console.log(str)
}
Or, a lot more concise:
str = str.replace(/_[0-9]+$/g, "")

Categories