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

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

Related

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 to replace string between two string with the same length

I have an input string like this:
ABCDEFG[HIJKLMN]OPQRSTUVWXYZ
How can I replace each character in the string between the [] with an X (resulting in the same number of Xs as there were characters)?
For example, with the input above, I would like an output of:
ABCDEFG[XXXXXXX]OPQRSTUVWXYZ
I am using JavaScript's RegEx for this and would prefer if answers could be an implementation that does this using JavaScript's RegEx Replace function.
I am new to RegEx so please explain what you do and (if possible) link articles to where I can get further help.
Using replace() and passing the match to a function as parameter, and then Array(m.length).join("X") to generate the X's needed:
var str = "ABCDEFG[HIJKLMN]OPQRSTUVWXYZ"
str = str.replace(/\[[A-Z]*\]/g,(m)=>"["+Array(m.length-1).join("X")+"]")
console.log(str);
We could use also .* instead of [A-Z] in the regex to match any character.
About regular expressions there are thousands of resources, specifically in JavaScript, you could see Regular Expressions MDN but the best way to learn, in my opinion, is practicing, I find regex101 useful.
const str="ABCDEFG[HIJKLMN]OPQRSTUVWXYZ";
const run=str=>str.replace(/\[.*]/,(a,b,c)=>c=a.replace(/[^\[\]]/g,x=>x="X"));
console.log(run(str));
The first pattern /\[.*]/ is to select letters inside bracket [] and the second pattern /[^\[\]]/ is to replace the letters to "X"
We can observe that every individual letter you wish to match is followed by a series of zero or more non-'[' characters, until a ']' is found. This is quite simple to express in JavaScript-friendly regex:
/[A-Z](?=[^\[]*\])/g
regex101 example
(?= ) is a "positive lookahead assertion"; it peeks ahead of the current matching point, without consuming characters, to verify its contents are matched. In this case, "[^[]*]" matches exactly what I described above.
Now you can substitute each [A-Z] matched with a single 'X'.
You can use the following solution to replace a string between two square brackets:
const rxp = /\[.*?\]/g;
"ABCDEFG[HIJKLMN]OPQRSTUVWXYZ".replace(rxp, (x) => {
return x.replace(rxp, "X".repeat(x.length)-2);
});

How to match regular expression In Javascript

I have string [FBWS-1] comes first than [FBWS-2]
In this string, I want to find all occurance of [FBWS-NUMBER]
I tried this :
var term = "[FBWS-1] comes first than [FBWS-2]";
alert(/^([[A-Z]-[0-9]])$/.test(term));
I want to get all the NUMBERS where [FBWS-NUMBER] string is matched.
But no success. I m new to regular expressions.
Can anyone help me please.
Note that ^([[A-Z]-[0-9]])$ matches start of a string (^), a [ or an uppercase ASCII letter (with [[A-Z]), -, an ASCII digit and a ] char at the end of the string. So,basically, strings like [-2] or Z-3].
You may use
/\[[A-Z]+-[0-9]+]/g
See the regex demo.
NOTE If you need to "hardcode" FBWS (to only match values like FBWS-123 and not ABC-3456), use it instead of [A-Z]+ in the pattern, /\[FBWS-[0-9]+]/g.
Details
\[ - a [ char
[A-Z]+ - one or more (due to + quantifier) uppercase ASCII letters
- - a hyphen
[0-9]+ - one or more (due to + quantifier) ASCII digits
] - a ] char.
The /g modifier used with String#match() returns all found matches.
JS demo:
var term = "[FBWS-1] comes first than [FBWS-2]";
console.log(term.match(/\[[A-Z]+-[0-9]+]/g));
You can use:
[\w+-\d]
var term = "[FBWS-1] comes first than [FBWS-2]";
alert(/[\w+-\d]/.test(term));
There are several reasons why your existing regex doesn't work.
You trying to match the beginning and ending of your string when you
actually want everything in between, don't use ^$
Your only trying to match one alpha character [A-Z] you need to make this greedy using the +
You can shorten [A-Z] and [0-9] by using the shorthands \w and \d. The brackets are generally unnecessary.
Note your code only returns a true false value (your using test) ATM it's unclear if this is what you want. You may want to use match with a global modifier (//g) instead of test to get a collection.
Here is an example using string.match(reg) to get all matches strings:
var term = "[FBWS-1] comes first than [FBWS-2]";
var reg1 = /\[[A-Z]+-[0-9]\]/g;
var reg2 = /\[FBWS-[0-9]\]/g;
var arr1 = term.match(reg1);
var arr2 = term.match(reg2)
console.log(arr1);
console.log(arr2);
Your regular expression /^([[A-Z]-[0-9]])$/ is wrong.
Give this regex a try, /\[FBWS-\d\]/g
remove the g if you only want to find 1 match, as g will find all similar matches
Edit: Someone mentioned that you want ["any combination"-"number"], hence if that's what you're looking for then this should work /\[[A-Z]+-\d\]/

javascript find protocol, domain, plus first slash with regexp from a src tag, replace with empty string

I tried to construct a regex for this task but I'm afraid I am still failing to have an intuitive understanding of regexp.
The problem is the regex matches until the last slash in a string. I want it to stop at the first match of the string.
My pathetic attempt at regex:
/^http(s?):\/\/.+\/{1}/
Test subject:
http://foo.com/bar/test/foo.jpeg
The goal is to obtain bar/test/foo.jpeg, so that I may then split the string, pop the last element and then join the remainder, resulting in having the path to the JavaScript file.
Example
var str = 'http://foo.com/bar/test/foo.jpeg';
str.replace(regexp,'');
While the other answer shows how to match a part of a string, I think a replace solution is more appropriate for the current task.
The issue you have is that .+ matches one or more characters other than a newline greedily, that is, all the string is grabbed first in one go, and then the regex engine starts backtracking (moving backwards along the input string looking for a / to accommodate in the match). Thus, you get the match from http until the last /.
To restrict the match from http to the first / use a negated character class [^/]+ instead of .+.
^https?:\/\/[^\/]+\/
^^^^^^
See the regex demo
Note that you do not need to place s into a capturing group to make it optional, unescaped ? is a quantifier that makes the preceding character match one or zero times. Also, {1} is a redundant quantifier since this is default behavior, c will only match 1 c, (?:something) will only match one something.
var re = /^https?:\/\/[^\/]+\//;
var str = 'http://foo.com/bar/test/foo.jpeg';
var result = str.replace(re, '');
document.getElementById("r").innerHTML = result;
<div id="r"/>
Note that you will need to assign the replace result to some variable, since in JS, strings are immutable.
Regex explanation:
^ - start of string
https? - either http or https substring
:\/\/ - a literal sequence of ://
[^\/]+ - 1 or more characters other than a /
\/ - a literal / symbol
Use capturing group based regex.
> var s = "http://foo.com/bar/test/foo.jpeg"
> s.match(/^https?:\/\/[^\/]+((?:\/[^\/]*)*)/)[1]
'/bar/test/foo.jpeg'

Regex with dynamic length

I have string with 2 or 3 words:
'apple grape lemon'
'apple grape'
I need to get first char from all words.
my regex:
/^(\w).*?\ (\w).*?\ ?(\w?).*?$/
For all strings this regex get only first char of 2 words.
How to fix?
You cannot do this with one regex (unless you are using .NET). But you can use a regex that matches one first character of a word, then get all the matches, and join them together:
var firstLetters = '';
var match = str.match(/\b\w/g)
if (match)
firstLetters = match.join('');
Of course if you just want to get the letters on their own, there is no need for the join, since the match will simply be an array containing all those letters.
You should not, that \w is not only letters, but digits and underscores, too.
If you work with javascript, you don't need to regex the hell out of a simple problem.
To get the first letter, just do that:
var aString = 'apple bee plant';
var anArray = aString.split(' ');
for(var aWord in anArray) {
var firstLetter = aWord.charAt(0);
}
Regular expressions are a regular language, such that you cannot have this kind of repetition in them. What you want is to cut the string into individual tokes (which can be done via regular expressions to match the separator) and then apply an regular expression on each token. To get the first char from each word it is faster to use a substring operation instead of a regular expression.
The problem with your regex is that the .*? after the second word eats up all the following content as everything afterwards is optional. This could be solved, but I personally think it makes things more complicated than required.
The most simple way would be:
firstLetters = (m = str.match(/\b\w/g))? m.join('') : '';
In regexp "words" don't mean only letters. In JavaScript \w is equals [A-Za-z0-9_]. So if you want only letters in your result, you can use [A-Za-z].

Categories