Regex matching for nock tests failing - javascript

I am trying to match URLs.
lab.before(async () => {
nock('https://dev.azure.com')
.get(centosAzureUri)
.times(5)
.reply(201, [
...
If I use a string, it is working just fine. An example is below:
const centosAzureUri = `/${conf.org}/${conf.buildProject}/_apis/build/builds?api-version=4.1&branchName=${conf.buildBranch}`
However, I want to use a RegEx as below:
const centosAzureUri = new RegExp(`/${conf.org}/${conf.buildProject}/_apis/build/builds?api-version=4.1.*`, 'g')
That is not working.
According to the documentation, nock should accept regular expressions and .* should match any symbol [because of the .] and allow those matched characters to be repeated any number of times. Hence, I am assuming this should accept any string ending, including &branchName=${conf.buildBranch}.
What I am doing wrong?

I think nock only uses regex literal vs. regex object which will return a new object. eg.
nock('http://example.com')
.get(/harry\/[^\/]+$/)
.query({param1: 'value'})
.reply(200, "OK");
See related
How to build nock regex for dynamic urls

Please note that RegExp only needs the pattern up to "4.1" to perform a match. The rest of the string will be ignored if the match occurs. For example:
const centosAzureUri = new RegExp(`/${conf.org}/${conf.buildProject}/_apis/build/builds?api-version=4.1`, 'g')
Further, you may want to try escapements, since slashes require those:
const centosAzureUri = new RegExp(`\/${conf.org}\/${conf.buildProject}\/_apis\/build\/builds?api-version=4.1`, 'g')
HTH!

Related

How do I use a regular expression from a string variable

In my current project, I have a CMS that is supplying all the data. One field of that CMS is for regular expressions, which allows me to enter my own specific expressions to check in the front end. My problem is that when I pull the regular expression it is coming through the escaped characters, and I can not seem to find a way to get around this.
The expression that I am using is /^\d+$/. As I mentioned this is stored inside my CMS and I am attempting to use it in the following code:
const re = /^\d+$/;
const rea = new RegExp(this.question.QuestionExpression);
console.log(re);
console.log(rea);
console.log(this.answer)
console.log(re.test(this.answer));
console.log(rea.test(this.answer));
console.log(this.answer.toString().match(this.question.QuestionExpression))
this.question.QuestionExpression is the Regular expression that is coming in from the CMS. The problem is not getting it, but how to interperet once I have it. const re is currently just being used as a test and has no real bearing on the final outcome.
The outcome from the above code is as follows:
/^\d+$/
/\/^\d+$\//
13
true
false
null
As you can see in the second line, it is adding escape characters which are causing it to fail on the 5th line. I am sure that I am missing something simple, but any advice would be greatly appreciated.
You don't include the / at the start and end when you are using a RegExp from a string.
const pattern = new RegExp('^a.*z');
console.log(pattern.test('abcdefghijklmnopqrstuvwxyz'));
console.log(pattern.test('zydhfkjadhsfkjlahsdkla'));
So, if your string is including those slashes, or may include those slashes, simply strip them off:
const strWithSlashes = '/abc/';
const str = strWithSlashes.replace(/(^\/|\/$)/g, '');
console.log(str);
const pattern = new RegExp(str);
console.log(pattern.test('cake abc cookies'));
console.log(pattern.test('cake cookies'));
If your regex from the CMS looks like /^\d+$/ it is likely the string representation of the regex. In contrast, new RegExp() expects a string representing the regex pattern without the leading and trailing /, so you need to strip them:
const fromCMS = '/^\\d+$/'; // escaped `\` so that string becomes `/^\d+$/`
const re1 = /^\d+$/;
const re2 = new RegExp(fromCMS.replace(/^\//, '').replace(/\/$/, ''));
console.log(re1);
console.log(re2);
[ '12', '2x' ].forEach(str => {
console.log(str + ' => re1: ' + re1.test(str) + ', re2: ' + re2.test(str));
});
Output:
/^\d+$/
/^\d+$/
12 => re1: true, re2: true
2x => re1: false, re2: false
In case the regex string from the CMS contains modifiers you can extract that, and supply as a second parameter to the new RegExp()

Find and replace complex term in a string using Regex

I Need to wrap any expression in a string (it can be multiline string with many expressions, mixed with regular words) that starts with abc.(efg|xyz).bar. with curly braces.
I'm using find and replace approach using the following Regex:
const MY_REGEX = /"?(?<![a-zA-Z0-9-_])((?:abc\.(efg|xyz\.bar))(?:\.[a-zA-Z0-9-_]*)+)"?/gm
someInput.replace(MY_REGEX, '{{$1}}')
My strategy works fine for simple cases like this:
const input = 'abc.efg.bar.name.first, abc.xyz.role, non.captured.term'
// outputs: {{abc.efg.bar.name.first}}, {{abc.xyz.role}}, non.captured.term
But fails miserably for a complex inputs like this one:
const input = 'abc.xyz.bar.$func(foos[param[name="primary" and bool=true]].param[name="new"].multiValue)'
// outputs: {{abc.xyz.bar.}}$func(foos[param[name="primary" and bool=true]].param[name="new"].multiValue)
// Should be: {{abc.xyz.bar.$func(foos[param[name="primary" and bool=true]].param[name="new"].multiValue)}}
I'm looking for a more robust way or better regex to do it.
Any suggestions?
Based on the examples you gave, it looks like , should be the delimiter between expressions. So (?:\.[a-zA-Z0-9-_]*)+) to [^,]* to match everything until the next ,.
const MY_REGEX = /"?(?<![a-zA-Z0-9-_])((?:abc\.(efg|xyz\.bar))[^,]*)"?/gm;
console.log('abc.xyz.bar.$func(foos[param[name="primary" and bool=true]].param[name="new"].multiValue)'.replace(MY_REGEX, '{{$1}}'));
console.log('abc.efg.bar.name.first, abc.xyz.role, non.captured.term'.replace(MY_REGEX, '{{$1}}'));

How to get content using filter and match?

I want to search in the array if theres the string that Im looking for, to do that im using match
const search_notes = array_notes.filter(notes => notes.real_content.toUpperCase().match(note.toUpperCase()));
as you can see, search_notes will give me an array with all the strings that at least has a character from the input or match completely, but theres a problem, because when I write , ), [], + or any regex symbol in the input it will gives me this error:
how can i solve this?
If you look at documentation for the match method (for instance, MDN's), you'll see that it accepts a RegExp object or a string, and if you give it a string, it passes that string into new RegExp. So naturally, characters that have special meaning in a regular expression need special treatment.
You don't need match, just includes, which doesn't do that:
const search_notes = array_notes.filter(
notes => notes.real_content.toUpperCase().includes(note.toUpperCase())
);

Match only # and not ## without negative lookbehind

Using JavaScript, I need a regex that matches any instance of #{this-format} in any string. My original regex was the following:
#{[a-z-]*}
However, I also need a way to "escape" those instances. I want it so that if you add an extra #, the match gets escaped, like ##{this}.
I originally used a negative lookbehind:
(?<!#)#{[a-z-]*}
And that would work just fine, except... lookbehinds are an ECMAScript2018 feature, only supported by Chrome.
I read some people suggesting the usage of a negated character set. So my little regex became this:
(?:^|[^#])#{[a-z-]*}
...which would have worked just as well, except it doesn't work if you put two of these together: #{foo}#{bar}
So, anyone knows how can I achieve this? Remember that these conditions need to be met:
Find #{this} anywhere in a string
Be able to escape like ##{this}
Be able to put multiple adjacent, like #{these}#{two}
Lookbehinds must not be used
If you include ## in your regex pattern as an alternate match option, it will consume the ## instead of allowing a match on the subsequent bracketed entity. Like this:
##|(#{[a-z-]*})
You can then evaluate the inner match object in javascript. Here is a jsfiddle to demonstrate, using the following code.
var targetText = '#{foo} in a #{bar} for a ##{foo} and #{foo}#{bar} things.'
var reg = /##|(#{[a-z-]*})/g;
var result;
while((result = reg.exec(targetText)) !== null) {
if (result[1] !== undefined) {
alert(result[1]);
}
}
You could use (?:^|[^#])# to match the start of the pattern, and capture the following #{<sometext>} in a group. Since you don't want the initial (possible) [^#] to be in the result, you'll have to iterate over the matches manually and extract the group that contains the substring you want. For example:
function test(str) {
const re = /(?=(?:^|[^#])(#{[a-z-]*}))./g;
let match;
const matches = [];
while (match = re.exec(str)) {
matches.push(match[1]); // extract the captured group
}
return matches;
}
console.log(test('##{this}'))
console.log(test('#{these}#{two}'))

JavaScript RegEx to match url path

I have possible url paths as below
/articles
/payment
/about
/articles?page=1
/articles/hello-world
I would like to match only the main path of the url, expected matches: ['articles', 'payment', 'about', 'articles', 'articles']
So I tried to construct the JavaScript RegEx and came up with as nearest as I can [a-z].*(?=\/|\?), unfortunately it only matches string inside the last two
Please guide
Thanks everyone
https://regex101.com/r/A86hYz/1
/^\/([^?\/]+)/
This regex captures everything between the first / and either the second / or the first ? if they exist. This seems like the pattern you want. If it isn't, let me know and I'll adjust it as needed. Some simple adjustments would be capturing what's between every / as well as capturing the query parameters.
For future reference, when writing regex, try to avoid the lookahead/behind unless you have to as they usually introduce bugs. It's easiest if you stick to using the regular operators.
To access the match, use the regex like this:
var someString = '/articles?page=1';
var extracted = someString.match(/^\/([^?\/]+)/)[1]
or more generally
function getMainPath(str) {
const regex = /^\/([^?\/]+)/;
return str.match(regex)[1];
}

Categories

Resources