简体   繁体   中英

Pass an array of strings into JavaScript indexOf()? Example: str.indexOf(arrayOfStrings)?

I need to be able to check a URL to see if it contains a second level domain (SLD) for a valid streaming service. Note, the "hulu" in www.hulu.com is what I mean by an SLD.

Rather than parsing the URL with regex to get just the SLD, or using something like location.hostname.split('.').pop() to get the SLD, I thought I could use indexOf instead. And this works great (for me at least, I realize it's got at least one serious limitation - see my note below).

Example. Let's say I want to see if https://www.hulu.com/watch/... is an Hulu link. This works:

let string = 'https://www.hulu.com/watch/...';
string.indexOf('hulu') > -1 ? true : false; // returns true

What I want to be able to do is pass an array of possible strings into indexOf. Something like this:

let validSLDs = ['hulu','netflix']

let string1 = 'www.hulu.com/watch/...';
let string2 = 'http://www.netflix.com/watch/...';
let string3 = 'imdb.com/title/....'

string1.indexOf(validSLDs); // returns true ('hulu' is a valid SLD)
string2.indexOf(validSLDs); // returns true ('netflix' is a valid SLD)
string3.indexOf(validSLDs); // returns false ('imdb' is not a valid SLD)

But of course this doesn't work because indexOf() is expecting to be passed a string, not an array of strings.

So is there some similarly easy, elegant (vanilla JS) solution that I'm not thinking of?

The next easiest thing I could think of would be to loop through my array of validSLDs and call indexOf on each of the SLDs. And maybe that is the best approach. I just thought I'd see if anyone else had a better solution. Thanks in advance!

NOTE: I realize that my entire approach is a lazy approach and could result in possible issues. For example, https://www.amazon.com/how-cancel-hulu-subscription-membership/... would also return true using the code above, because the word "hulu" exists in the string... but isn't an SLD. I'm ok with that because we have some control over the URL's we need to validate.

Just make a little helper function that does what you said, loops through the array and checks each value. An efficient way to do that is with Array.some , as it will return true as soon as it finds a truthy match.

 let validSLDs = ['hulu','netflix'] let string1 = 'www.hulu.com/watch/...'; let string2 = 'http://www.netflix.com/watch/...'; let string3 = 'imdb.com/title/....' const isURLOK = (testString) => validSLDs.some(v => testString.indexOf(v) > -1); console.log(isURLOK(string1)); console.log(isURLOK(string2)); console.log(isURLOK(string3));

let string1 = 'www.hulu.com/watch/...';
let string2 = 'http://www.netflix.com/watch/...';
let string3 = 'imdb.com/title/....'
let unverfiedSLDs = [string1, string2, string3]
let validSLDs = ['hulu', 'netflix', 'imdb'];

let allSLDsAreValid = unverifiedSLDs.every(s => controlSLDs.includes(s))

allSLDsareValid is a boolean, it evaluates to true if all strings are valid, and false if there is at least one invalid string.

If instead you want to keep track of which SLDs are valid and which are not, try using an object:

let validatedStrings = {}
unverifiedSLDs.forEach(s => {
    if (validSLDs.includes(s)) {
        SLDs[s] = true;
    }
})

Then when you need to access the SLD's validity, you can check for the key existence in validatedStrings:

validatedStrings[string1] = true
validatedStrings[string2] = true
validatedStrings[string3] = true
validatedStrings['not-valid'] = undefined

I really appreciate all the suggestions. Ultimately I went with a combination of suggestions and did the following.

let link = 'www.imdb.com/title/...';

validateLink = (link) => {
  let validSLDs = ['hoopla', 'kanopy' ... ];

  for(let i in validSLDs) {
    if(link.includes(validSLDs[i])) {
      return true;
    };
  };
  return false;
};

Which seems to work just fine (although it isn't bulletproof, as mentioned in my original NOTE and in a comment). Passing the IMDB link into the function returned false, while passing a hoopla or kanopy link returned true. I might try and refactor a bit more... but this should work for my purposes.

Then Peter Seliger wrote an even more succinct version (below) that works even better. Especially if you're not confused by nested arrow functions. Click on the "Run Code Snippet" button below to see Peter's improved answer in action.

Thanks again for the help everyone!

Edit by Peter Seliger in order to clarify some code behavior

Q: OP in comment ...

"... But I ran into some issues. So then I tried copy/pasting your solution into codepen and I'm getting a TypeError: cannot read property 'includes' of undefined. ..."

A:

If I do a copy and paste into eg the browser console, and do invoke validateLink('https://www.hulu.com/watch/...') it returns false... invoking validateLink('https://www.hoopla.com/watch/...') returns true.

And even if ['hoopla', 'kanopy', /*...*/] inside the function was a sparse array (array with empty slots, which it is not) the iteration would work, because every array method skips empty slots.

executable code snippet for proofing the above said...

 const validateLink = link => ['hoopla', 'kanopy', /*...*/].some(sdl => link.includes(sdl)); console.log( "validateLink('https://www.hulu.com/watch/...')?", validateLink('https://www.hulu.com/watch/...') // false ); console.log( "validateLink('https://www.hoopla.com/watch/...')?", validateLink('https://www.hoopla.com/watch/...') // true );

you could try to use the filter function of arrays:

let validSLDs = ['hulu','netflix']

let string1 = 'www.hulu.com/watch/...';
let string2 = 'http://www.netflix.com/watch/...';
let string3 = 'imdb.com/title/....'

validSLDs.filter(sld => string1.indexOf(sld) !== -1).length > 0; // returns true ('hulu' is a valid SLD)
validSLDs.filter(sld => string2.indexOf(sld) !== -1).length > 0; // returns true ('netflix' is a valid SLD)
validSLDs.filter(sld => string3.indexOf(sld) !== -1).length > 0; // returns false ('imdb' is not a valid SLD)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM