How to match string with hypens in JavaScript? - 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]);
}

Related

Conditional(?) regex for numbers

i was trying to create a regex that could match numbers within brackets or not, for example:
(1.000.000,00) //match
(1.000,00) //match
(100,00) //match
(10) //match
(1) //match
(2.000.000,00 //dont't match
(2.000,00 //dont't match
(200,00 //dont't match
(20 //dont't match
(2 //dont't match
3.000.000,00) //dont't match
3.000,00) //dont't match
300,00) //dont't match
30) //dont't match
3) //dont't match
4.000.000,00 //should match
4.000,00 //should match
400,00 //should match
40 //should match
4 //should match
I need to match only numbers(in brackets or not), but only if they have all brackets (2) or none(0)
At the moment this is what i came up with: \((\d+[\.,]?)+\d*\), it matches the --match and doesn't match the --don't match but should match also the --should match
I've added the javascript tag because i'm using this regex in js and not all of the regex tokens work in the js regex constructor
I'm posting also a regex101 link
If supported, you can usea negative lookbehind to match either with or without parenthesis:
\(\d+(?:[.,]\d+)*\)|(?<!\S)\d+(?:[.,]\d+)*(?!\S)
\( Match (
\d+(?:[.,]\d+)* Match 1+ digits and optionally repeat matching . or , and again 1+ digits
\) Match )
| Or
(?<!\S) Negative lookbehind, assert a word boundary to the left
\d+(?:[.,]\d+)* Match 1+ digits and optionally repeat matching . or , and again 1+ digits
(?!\S) Negative lookahead, assert a whitespace boundary to the right
Regex demo
Another option could be matching optional parenthesis at both sides, and only keep the ones that have either an opening and closing parenthesis, or none.
const regex = /\(?\d+(?:[.,]?\d+)*\)?/
const strings = ["(1.000.000,00)", "(1.000,00)", "(100,00)", "(10)", "(1)", "(2.000.000,00", "(2.000,00", "(200,00", "(20", "(2", "3.000.000,00)", "3.000,00)", "300,00)", "30)", "3)", "4.000.000,00", "4.000,00", "400,00", "40", "4"];
strings.forEach(s => {
const m = s.match(regex);
const firstChar = s.charAt(0);
const lastChar = s.charAt(s.length - 1);
if (
m &&
(firstChar !== '(' && lastChar !== ')') ||
firstChar === '(' && lastChar === ')'
) {
console.log(s)
}
});
If you don't want to repeat the part matching numbers (which in this case is short, so maybe an exception to the DRY rule is warranted), you can reach for \(?((\d+[\.,]?)+\d*)\)?(?<=\(\1\)|(^|[^(\d.,])\1(?=($|[^\d.,)]))).
Edit: this is broken.
It will match numbers like (7 as it only matches the number and ignores the parentheses in that case.
Kept here for future reference.
It's usually easier to do regex in multiple passes, but here goes:
/(\((\d+[\.,]?)+\d*\))|(\d+[\.,]?\d*)/gm
You can test it on https://regex101.com/.
Usually it's better to process something in multiple passes as you can see the regex becomes even more unreadable.
I took your regex and just split it into two regexes: one that requires the parentheses and one that doesn't, then combined them with the or operator.
Note that this regex will allow things like "123.3,5.7" as one number, and the capturing groups will be nasty.

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

regular expression to validate a pattern

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

Regex: Everything until last occurrence of pattern

Given the following strings:
'/a/xxx/b/c/xxx/xxx/d/e/xxx/xxx/f/g'
'/a/xxx/b/c/xxx/xxx/d/e/xxx/xxx/f/'
'/a/xxx/b/c/xxx/xxx/d/e/xxx/xxx/f'
'/a/xxx/b/c/xxx/xxx/d/e/xxx/xxx/f/g/xxx/xxx'
I'm looking for a regex that will match
/a/xxx/b/c/xxx/xxx/d/e/xxx/xxx/f
for all of the above strings
That is, match everything until the last occurrence of this pattern:
{forward slash or start of string} then {xxx} then {forward slash} then {any group of chars (except forward slash) that is not equal to xxx } then {forward slash or end of string}
I do not know how to translate the above pattern into a regex.
The .*\/ pattern I tried does not solve the problem.
You may use
/(?:.*\/)?xxx\/(?!xxx(?![^\/]))[^/]*(?=$|\/)/
See the regex demo.
Details
(?:.*\/)? - an optional group matching
.* - any 0+ chars other than line break chars, as many as possible
\/ - a / char
xxx\/ - a xxx/ substring
(?!xxx(?![^\/])) - the text starting at the next location in string cannot be equal to xxx/ or xxx at the end of the string
[^/]* - any 0+ chars other than / as many as possible ([^/]*)
(?=$|\/) - there must be end of string or / immediately to the right of the current position.
JS demo:
var strs = ['/a/xxx/b/c/xxx/xxx/d/e/xxx/xxx/f/g','/a/xxx/b/c/xxx/xxx/d/e/xxx/xxx/f/','/a/xxx/b/c/xxx/xxx/d/e/xxx/xxx/f','/a/xxx/b/c/xxx/xxx/d/e/xxx/xxx/f/g/xxx/xxx','/xxx/f/g','xxx/f/g','a/xxx/f/g','/a/xxx/f/g','/a/xxx/b/c/xxx/xxx/d/e/xxx/gggxxxd/f/gxxxf/'];
var rx = /(?:.*\/)?xxx\/(?!xxx(?![^\/]))[^/]*(?=$|\/)/;
for (var s of strs) {
console.log(s, "=>", s.match(rx)[0]);
}

Javascript Regex: negative lookbehind

I am trying to replace in a formula all floating numbers that miss the preceding zero. Eg:
"4+.5" should become: "4+0.5"
Now I read look behinds are not supported in JavaScript, so how could I achieve that? The following code also replaces, when a digit is preceding:
var regex = /(\.\d*)/,
formula1 = '4+1.5',
formula2 = '4+.5';
console.log(formula1.replace(regex, '0$1')); //4+10.5
console.log(formula2.replace(regex, '0$1')); //4+0.5
Try this regex (\D)(\.\d*)
var regex = /(\D)(\.\d*)/,
formula1 = '4+1.5',
formula2 = '4+.5';
console.log(formula1.replace(regex, '$10$2'));
console.log(formula2.replace(regex, '$10$2'));
You may use
s = s.replace(/\B\.\d/g, '0$&')
See the regex demo.
Details
\B\. - matches a . that is either at the start of the string or is not preceded with a word char (letter, digit or _)
\d - a digit.
The 0$& replacement string is adding a 0 right in front of the whole match ($&).
JS demo:
var s = "4+1.5\n4+.5";
console.log(s.replace(/\B\.\d/g, '0$&'));
Another idea is by using an alternation group that matches either the start of the string or a non-digit char, capturing it and then using a backreference:
var s = ".4+1.5\n4+.5";
console.log(s.replace(/(^|\D)(\.\d)/g, '$10$2'));
The pattern will match
(^|\D) - Group 1 (referred to with $1 from the replacement pattern): start of string (^) or any non-digit char
(\.\d) - Group 2 (referred to with $2 from the replacement pattern): a . and then a digit

Categories