JavaScript: Can I use the filter function with regular expressions? - javascript

I tried to find a similar question to avoid creating a duplicate and I couldn’t, but I apologise if I missed any. I've just started learning how to code and I've encountered this problem:
With JavaScript, I want to use the filter arrays method (https://www.freecodecamp.org/challenges/filter-arrays-with-filter) with a general expression for all non alphanumeric characters.
For example:
var newArray = oldArray.filter(function(val) {
return val !== /[\W_]/g;
});
Can I do that? In the mozilla guide (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) it mentions you can use regular expressions with replace, and I understand how to do that, but it doesn’t mention filter at all.
To put another less abstract example, this is the code I’m working on:
function palindrome(str) {
var splitStr = str.split("");
var filterArray = splitStr.filter(function(val) {
return val !== /[\W_]/g;
});
return filterArray;
}
palindrome("ey*e");
If I’m doing things right so far, the function should return [“e”, “y”, “e”]. But it returns [“e”, “y”, “*”, “e”] (as if I hadn’t filtered it at all). I just wonder if I’ve made a mistake in my code, or if one simply can’t use filter with regular expressions.
If that's the case, why? Why can't one use filter with regular expressions!? Why do we have to use replace instead?

This really isn't an issue relating to .filter(), it's just that you aren't testing your string against your regular expression properly.
To test a string against a regular expression you use the .test() method:
function palindrome(str) {
var splitStr = str.split("");
var filterArray = splitStr.filter(function(val) {
// Test the string against the regular expression
// and test for no match (whole thing is preceeded by !)
return !/[\W_]/g.test(val);
});
return filterArray;
}
console.log(palindrome("ey*e"));

Instead of first splitting the string into chars, and then test every single one of them, why don't you just get all matches for the string?
function palindrome(str) {
return str.match(/[a-zA-Z0-9]/g) || [];
}
let chars = palindrome("ey*e");
console.log(chars);
About the used regex: \W is the same as [^\w] or [^a-zA-Z0-9_]. So, not [\W_] is equivalent to [a-zA-Z0-9].

Related

Regex do not match content but whole searched string

I'm using this regex to match an "href" attribute in a <a> tag:
var href_matches = postRep.match(/href="(.*?)"/g);
The regex matches correctly the href except it returns the whole "href=http:example.com" string.
How do I manage to get only the href value (eg. "example.com")?
You can either run exec() on the regex :
var url_match = /href="(.*?)"/g.exec(postRep);
or remove the global flag
var url_match = postRep.match(/href="(.*?)"/);
Using String's match() function won't return captured groups if the
global modifier is set.
Just another idea.
You can try something like this function:
function getHrefs(inputString) {
var out = [];
inputString.replace(/\bhref\b=['"]([^'"]+)['"]/gi, function(result, backreference) {
out.push(backreference);
return '';
});
return out;
}
Improved solution (much shortest):
function getHrefs(inputString) {
return (inputString.match(/\bhref\b=['"][^'"]+(?=['"])/gi) || []).map(s => s.replace(/^href=["']/,""));
}
Edit:
There is other option - exec. But with exec you will need loop to get all matches (if you need this).
You can use regex lookbehinds to check if the "href=" is there without actually including it in the match.
For example, the regex (?<=href=)example\.com applied to href=example.com should only match example.com.
EDIT:
This method only works in languages that support regex lookbehinds. Javascript doesn't support this feature. (thanks to Georgi Naumov for pointing this out)

change regex to match some words instead of all words containing PRP

This regex matches all characters between whitespace if the word contains PRP.
How can I get it to match all words, or characters in-between whitepsace, if they contain PRP, but not if they contain me in any case.
So match all words containing PRP, but not containing ME or me.
Here is the regex to match words containing PRP: \S*PRP\S*
You can use negative lookahead for this:
(?:^|\s)((?!\S*?(?:ME|me))\S*?PRP\S*)
Working Demo
PS: Use group #1 for your matched word.
Code:
var re = /(?:^|\s)((?!\S*?(?:ME|me))\S*?PRP\S*)/;
var s = 'word abcPRP def';
var m = s.match(re);
if (m) console.log(m[1]); //=> abcPRP
Instead of using complicated regular expressions which would be confusing for almost anyone who's reading it, why don't you break up your code into two sections, separating the words into an array and filtering out the results with stuff you don't want?
function prpnotme(w) {
var r = w.match(/\S+/g);
if(r == null)
return [];
var i=0;
while(i<r.length) {
if(!r[i].contains('PRP') || r[i].toLowerCase().contains('me'))
r.splice(i,1);
else
i++;
}
return r;
}
console.log(prpnotme('whattttttt ok')); // []
console.log(prpnotme('MELOLPRP PRPRP PRPthemeok PRPmhm')); // ['PRPRP', 'PRPmhm']
For a very good reason why this is important, imagine if you ever wanted to add more logic. You're much more likely to make a mistake when modifying complicated regex to make it even more complicated, and this way it's done with simple logic that make perfect sense when reading each predicate, no matter how much you add on.

Convert string to function with parameters

I am struggling with writing a regular expression to turn the string
"fetchSomething('param1','param2','param3')"
into the proper function call. I can do it with some splitting and substrings but would rather do it with a .match using capture groups for efficiency's sake (and my own education).
However when I use
'something("stuff","moreStuff","yetMoreStuff")'.match(/(?:\(|,)("?\w+"?)/g)
I get
["("stuff"", ","moreStuff"", ","yetMoreStuff""]
Which is the same result regardless of the ?:, this confuses me since I thought ?: would cause it to ignore the first capture group? Or am I completely miss understanding capture groups?
You get the whole string when you have the g flag active. If you're going only after the sub-matches, then you will need to use .exec and a loop:
var regex = /(?:\(|,)("?\w+"?)/g;
var s = 'something("stuff","moreStuff","yetMoreStuff")';
var match, matches=[];
while ( (match=regex.exec(s)) !== null ) {
matches.push(match[1]);
}
alert(matches);
jsfiddle

Return the part of the regex that matched

In a regular expression that uses OR (pipe), is there a convenient method for getting the part of the expression that matched.
Example:
/horse|caMel|TORTOISe/i.exec("Camel");
returns Camel. What I want is caMel.
I understand that I could loop through the options instead of using one big regular expression; that would make far more sense. But I'm interested to know if it can be done this way.
Very simply, no.
Regex matches have to do with your input string and not the text used to create the regular expression. Note that that text might well be lost, and theoretically is not even necessary. An equivalent matcher could be built out of something like this:
var test = function(str) {
var text = str.toLowerCase();
return text === "horse" || text === "camel" || text === "tortoise";
};
Another way to think of it is that the compilation of regular expressions can divorce the logic of the function from their textual representation. It's one-directional.
Sorry.
There is not a way built-in to the Javascript RegExp object; without changing your expression. The closest you can get is source which will just return the entire expression as a string.
Since you know you're expression is a series of | ORs, you could capturing groups to figure out which group matched, and combine that with .source to find out the contents of that group:
var exp = /(horse)|(caMel)|(TORTOISe)/i;
var result = exp.exec("Camel");
var match = function(){
for(var i = 1; i < result.length; i++){
if(result[i]){
return exp.source.match(new RegExp('(?:[^(]*\\((?!\\?\\:)){' + i + '}([^)]*)'))[1];
}
}
}();
// match == caMel
It is also extremely easy (although somewhat impractical) to write a RegExp engine from scratch would you could technically add that functionality to. It would be much slower than using an actual RegExp object, since the whole engine would have to be interpreted at run-time. It would, however, be able to return exactly the matched portion of the expression for any regular expression and not be limited to one which consists of a series of | ORs.
The best way to solve your problem, however, is probably not to use a loop or a regular expression at all, but instead to create an object where you use a canonical form for the key:
var matches = {
'horse': 'horse',
'camel': 'caMel',
'tortoise': 'TORTOISe'
};
// Test "Camel"
matches['Camel'.toLowerCase()]; // "caMel"
This will give the wanted value without looping:
var foo, pat, tres, res, reg = /horse|caMel|TORTOISe/i;
foo = reg.exec('Camel');
if (foo) {
foo = foo[0].replace(/\./g, '\\.');
pat = new RegExp('\\|' + foo + '\\|', 'i');
tres = '|' + reg.source + '|';
res = tres.match(pat)[0].replace(/\|/g, '');
}
alert(res);
If there's no match, now you get undefined, though it's easy to change to something else.

regular expression not working when provided in double quotes in javascript

I am trying to use regular expession in javascript but it is not working. My custom control contains property called RegEx which is provided by user and I need to validate the input value against this regex. As properties in JS will be in double quotes("") the regualr expression fails(case -1). Case 2 succeeds thought both the cases regualr expression is same, the only difference is case- 1 it goes as double quotes. can somebody tell me why it is not working.
RegexExp="/^\d{5}$/"- at my aspx page
var value = "11111";
if(value.toString().search($(element).attr('RegexExp')) != -1)
{
return true;
}
else
{
return false;
}
var reg = /^\d{5}$/;
if(value.toString().search(reg) != -1)
{
return true;
}
else
{
return false;
}
Do this instead:
var reg = new RegExp($(element).attr('RegexExp'));
Update: you also need to strip the / characters, as these shouldn't be given to the RegExp constructor:
var regexExp = $(element).attr('RegexExp');
var reg = new RegExp(regexExp.substring(1, regexExp.length - 1));
I assume that the code that you posted is part of the function from the return statements, but if it is not, your first problem is that return is not allowed to be used out side of functions.
In any case, try the following. You can create a RegExp from a string by using its formal constructor
value.search(new RegExp($(element).attr('RegexExp')));
Also, you do not need to use toString() on value since it is already a string and your code is unnecessarily verbose. The following is equivalent to your first if else statement
return value.search(new RegExp($(element).attr('RegexExp'))) != -1;
Edit:
If you want to be able to pass in an expression as "/[expression]/" or "/[expression]/gi", you can do the following:
var toRegExp = function(regexString) {
var expression = regexString.substr(1), // remove first '/'
closingSlash = expression.lastIndexOf("/"); // find last '/'
return new RegExp(
// Expression: remove everything after last '/'
expression.substr(0, closingSlash),
// Flags: get everything after the last '/'
expression.substr(closingSlash+1)
);
}
....
value.search( toRegExp($(element).attr('RegexExp')) );
First, don't use a custom attribute to hold a regular expression. Second, "RegexExp" is redundant — that's like saying "regular expression expression". Third, to convert from a String to a RegExp, you have to wrap the string with new RegExp(); JavaScript is not weakly typed. That said, assuming that the regular expression isn't being set server-side, I'd recommend using jQuery's data API. It has the added advantage that it can store regular expression objects directly.
To set:
jQuery.data($(element).get(0), "regexp", /^\d{5}$/);
To get:
jQuery.data($(element).get(0), "regexp");
But ultimately, what you really want is the jQuery Validation plugin. It does everything you need and then some. Incidentally, it uses the data API internally to work its magic.
Documentation
The /.../ syntax is used to declare a regular expression object in Javascript, so you shouldn't use that to specify a regular expression pattern, it should be just regexp="^\d{5}$" as the attribute.
The search method takes a regular expression object as parameter, so you have to create a regular expression object from the string that you get from the attribute:
var reg = new RegExp($(element).attr('regexp'));
if (value.toString().search(reg) != -1) {
(You see the similarity with your second case?)
Or as a single expression:
if (value.toString().search(new RegExp($(element).attr('regexp'))) != -1) {

Categories

Resources