32

I'm trying to filter an array that contains a bunch of urls. I need to return the urls that only contain the word "contact".

For example there is a link https://www.example.com/v1/contact-us/ca

This should be returned from the filter.

I tried this:

    const regex = new RegExp("/\bcontact\b", 'g' )
    sites.links.filter((val) => {

     console.log(regex.test(val.href))

    })

It currently just sends back false through all the domains, when I know there is one domain that contains the word "contact".

6
  • 1
    you need to return truthy/falsey in filter ... returning nothing === return undefined == return false ... also, you are discarding the result of filter anyway, so your code is mostly pointless Commented Oct 30, 2017 at 5:02
  • @JaromandaX ya silly spelling mistake. updated. so if I do regex.test(val.href) ? return val.href : null Commented Oct 30, 2017 at 5:05
  • const matchedSites = sites.links.filter(val => regex.test(val.href)); - note /\bconsole\b the first \b is redundant - and you'll want new RegExp("/contact\\b", 'g' ) ... so const regex = new RegExp('/contact\\b', 'g'); Commented Oct 30, 2017 at 5:06
  • @JaromandaX I get back 2 empty arrays with that Commented Oct 30, 2017 at 5:09
  • so if I do - no, read documentation first to learn how filter is used ... you may also need a refresher on RegExp Commented Oct 30, 2017 at 5:09

7 Answers 7

57

Firstly new RegExp('/\bcontact\b', 'g'); is equivalent to /\/@contact@/g where the @ are backspace character (ASCII 08) ... clearly not what you want

So, you would do new RegExp('/\\bcontact\\b', 'g'); - this is equivalent to /\/\bcontact\b/g

However, the \\b after / is redundant

so ... down to /\/contact\b/g

Using string.match here as regex.test is misused. Below is the description

var sites = { 
    links: [
        {href: 'https://www.example.com/v1/contact-us/ca'},
        {href: 'https://www.example.com/v1/contact-us/au'},
        {href: 'https://www.example.com/v1/contact-us/us'},
        {href: 'https://www.example.com/v1/dontcontact-us/us'}
    ]
};

const regex = new RegExp('/contact\\b', 'g');
const matchedSites = sites.links.filter(({href}) => href.match(regex));
console.log(matchedSites);

The next problem is using the ONE regex multiple times in a regexp.test with g flag. With each call, it will look from the next indexOf previous found substring and with consecutive calls on a same-type string, it basically will return true, false, true, false.

If you want to use regex.test, then don't re-use the same regex unless you know the consequences of doing so or do not use g flag (which here you do not need)

var sites = { 
    links: [
        {href: 'https://www.example.com/v1/contact-us/ca'},
        {href: 'https://www.example.com/v1/contact-us/au'},
        {href: 'https://www.example.com/v1/contact-us/us'},
        {href: 'https://www.example.com/v1/dontcontact-us/us'}
    ]
};

const regex = new RegExp('/contact\\b', 'g');
const correctRegex = new RegExp('/contact\\b');

const matchedSitesFailed = sites.links.filter(({href}) => regex.test(href));
const matchedSitesSuccess = sites.links.filter(({href}) => new RegExp('/contact\\b', 'g').test(href));
const matchedSitesSuccess2 = sites.links.filter(({href}) => correctRegex.test(href));

console.log('failed returns:', matchedSitesFailed.length);
console.log('success returns:', matchedSitesSuccess.length);
console.log('success returns 2:', matchedSitesSuccess2.length);

Sign up to request clarification or add additional context in comments.

3 Comments

I've expanded the answer too ... be careful with regex.test :p
@JaromandaX Thanks for your answer. However, I have one curious, when I use the regex.test for filtering, I missed some data matched with condition. What is the reason? Actually this issue is solved to use regex.match instead regex.test. Could you explain for it? Thanks.
One last thing that would help a lot that this answer doesn’t mention yet is regex literals.
8

You need to return the truthy / falsy result from filter function.

const sites = {
  links: [
    {
      href: 'http://www.some-site.com/contact-us',
    },
    {
      href: 'http://www.some-site.com/about',
    },
    {
      href: 'http://www.some-site.com/admin',
    },
  ],
};

const fitered = sites.links.filter((link) => {
  return link.href.split('/').some((part) => part.includes('contact'));
});

console.log(fitered);

4 Comments

Updated the answer to use regex.
no @Dileet - it's because the code is using filter correctly ... by the way, this code still can fail
@felixmosh - check jsfiddle.net/k2ry8xz7 - your code fails to return both contact pages, because you are using regex.test without understanding it
includes method saved my time! instead of using regex, this matched super easily my substrings. many thanks
3
var links = ["https://www.example.com/v1/contact-us/ca", "https://www.example.com/v1/contact-us/sanjose", "https://www.example.com/v1/meeting-us/ca"];

var newlink = links.filter(function(link){
  return link.includes("contact")
});

console.log(newlink)

Try this. It should work.

1 Comment

no no no ... this would match dontcontactusever
2
const regex = new RegExp('/contact\\b', 'g');
const matchedSites = sites.links.filter(e => 
  regex.test(e.href));
console.log(matchedSites);

2 Comments

explain your answer which will make your answer more acceptable and attracts more votes
While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value.
1

My take on this. OP requested regex.

const domains = [{href: 'https://foo'}, {href: 'https:://bar'}, {href: 'https:://bar/contact'}]
  const match = domain => {
    return RegExp('/contact\\b', 'g').test(domain.name)
  }
 const needle = domains.filter(domain.href => match(domain))

RegExp.test returns falsy, therefore you can use it directly as a return in the filter.

Comments

0

The best answer I could imagine is:

const sites = {
    links: {
        'http://www.some-site.com/contact-us',
        'http://www.some-site.com/about',
        'http://www.some-site.com/admin'
    }
};
sites.links.forEach(i => {
    console.log(i.search(/\/\bcontact\b/g) > -1);
});

sites.links.forEach() looping through all the links available

i => {/*...*/} ES6 syntax for function(i) {/*...*/}

console.log() logging the result

/\/\bcontact\b/g works the same as new RegExp("/\bcontact\b", "g") i.search(regexp) > -1, "string".search("s") means, it will search the letter "s" in "string" and return its index in the string, if "s" was not "found" in string, then -1 is returned, so we are checking for, is there "s" in "string" and returning the true/false value

The code's ES5 syntax:

sites.links.forEach(function(i) {
    console.log(i.search(/\/\bcontact\b/g) > -1);
});

Comments

0

this is a late reply, but for simplicity, bind is your friend.

let re = /dog/g;
let fn = re.exec.bind(re);
let strings = ['things','a dog is here','fruity ideas'];

let filtered = strings.filter(fn);

console.log({
  strings,
  filtered
})

how it works: filter returns all elements that the callback returns a "truthy" result for. RegExp.exec either returns null or a result set. null is falsey, so any callbacks returning null are filtered out.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.