0

I have a website where people can input a YouTube link into a textbox. I also want a tick icon appear adjacent to the input box if the link being typed is the beginning of a valid YouTube URL or a cross icon if it is not. Using Jquery I have tried doing this like so:

$(document).ready(function(){
$("#yt_input").keyup(function(){
    var link = $(this).val();
    var p = /(?:https?:\/\/)?(?:www\.)?((youtu.be|youtube\.com)\/(watch\?v=)).{10,13}$/;
    if(link.match(p)  !== null){
        $("#yt_input_status").attr("src", "tick_icon.png");
    } else {
        $("#yt_input_status").attr("src", "cross_icon.png");
    }
});


});

This works fine, however this only works if the whole (valid) url has been typed in. For example if the user types https which is the start of the valid url https://www.youtube.com/watch?v=jsidR6kBZ6A this cross icon will appear, not to be changed until the whole link has been given. I am not sure if this is just a question of modifying the RegEx to something such as "any of these characters in a certain order" or if there is jquery function similar to .contains() that supports RegEx. Is there a way to do this?
Any help would be greatly appreciated!

Casey Neistat
  • 61
  • 1
  • 2
  • 6

1 Answers1

1

That's not a smart idea since you'd basically showing an invalid link as if it was working normally, and also it may give you a lot of troubles while matching in real time.

So here is a better solution if you need: You may test if the current string is actually an URL, and while it's not, show a loading icon, for example, something like this: Type a valid URL to identify..., all you need to do is match if the text you're trying to match, is actually an URL.
Based on this answer, you can simply test it with the function:

function isURL(value) {
  return /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i.test(value);
}

And then, if the desired text is not an URL, you may just show another icon.

EXAMPLE RESULT:

if (isURL(link)){
    if(link.match(p) !== null){
        $("#yt_input_status").attr("src", "tick_icon.png");
    } else {
        $("#yt_input_status").attr("src", "cross_icon.png");
    }
} else {
    $("#yt_input_status").attr("src", "waiting_icon.gif"); //Example icon
}

But if you really mean to get a tick_icon instead while it's not a valid URL, you may use a regex to match it partially. This threat gives you a function to convert a regex to a partial matching regex Input:

/(?:https?:\/\/)?(?:www\.)?((youtu.be|youtube\.com)\/(watch\?v=)).{10,13}$/.toPartialMatchRegex();

Output:

/(?:(?:h|$)(?:t|$)(?:t|$)(?:p|$)(?:s|$)?(?::|$)(?:\/|$)(?:\/|$)|$)?(?:(?:w|$)(?:w|$)(?:w|$)(?:\.|$)|$)?(((?:y|$)(?:o|$)(?:u|$)(?:t|$)(?:u|$)(?:.|$)(?:b|$)(?:e|$)|(?:y|$)(?:o|$)(?:u|$)(?:t|$)(?:u|$)(?:b|$)(?:e|$)(?:\.|$)(?:c|$)(?:o|$)(?:m|$)|$)(?:\/|$)((?:w|$)(?:a|$)(?:t|$)(?:c|$)(?:h|$)(?:\?|$)(?:v|$)(?:=|$)|$)|$)(?:.|$){10,13}$/

FINAL RESULT:

var partialp = /(?:(?:h|$)(?:t|$)(?:t|$)(?:p|$)(?:s|$)?(?::|$)(?:\/|$)(?:\/|$)|$)?(?:(?:w|$)(?:w|$)(?:w|$)(?:\.|$)|$)?(((?:y|$)(?:o|$)(?:u|$)(?:t|$)(?:u|$)(?:.|$)(?:b|$)(?:e|$)|(?:y|$)(?:o|$)(?:u|$)(?:t|$)(?:u|$)(?:b|$)(?:e|$)(?:\.|$)(?:c|$)(?:o|$)(?:m|$)|$)(?:\/|$)((?:w|$)(?:a|$)(?:t|$)(?:c|$)(?:h|$)(?:\?|$)(?:v|$)(?:=|$)|$)|$)(?:.|$){10,13}$/;
var p = /(?:https?:\/\/)?(?:www\.)?((youtu.be|youtube\.com)\/(watch\?v=)).{10,13}$/;
if (!link.includes("youtu")) {
    if(link.match(partialp) !== null){
        $("#yt_input_status").attr("src", "tick_icon.png");
    } else {
        $("#yt_input_status").attr("src", "cross_icon.png");
    }
} else {
    if(link.match(p) !== null){
        $("#yt_input_status").attr("src", "tick_icon.png");
    } else {
        $("#yt_input_status").attr("src", "cross_icon.png");
    }
}

By the way, the problem of this way of testing is that sometimes it may not match as you've expected since it's partially testing the URL and testing only for the last character, always... You may see that it doesn't work with https://www.youtube.com/watch?=ew, because of the w at the end, matches with the w from www.. That's why the first option is preferable.

Just some notes to your regex:
- Your regex seem to be matching youtu.be/watch?v=BFxqR7EO8ho, which is not a valid YouTube URL since it'll redirect to youtube.com/watch?v=watch.
- Also, it won't match videos with custom parameters, such as https://www.youtube.com/watch?gl=GB&v=BFxqR7EO8ho&feature=youtu.be
- Nor other youtube special countries' links (i.e. youtube.com.br/... youtube.co.uk/...). But whatsoever, could you explain what is this 'invalid URL' that you meant to match?

Community
  • 1
  • 1
Mateus
  • 3,595
  • 4
  • 21
  • 32
  • Wow. Thank you so much for such a detailed explanation! – Casey Neistat Apr 30 '17 at 18:35
  • Testing your partial regex in [Rubular](http://rubular.com) it says "forward slashes must be escaped" and when I remove all forward slashes it doesn't match anything. Any ideas why? – Casey Neistat Apr 30 '17 at 21:27
  • @CaseyNeistat That's probably because Rubular doesn't require the slashes indicator. You're testing the whole regex (`/..../`), try removing the first and last forward slashes (i.e. `/..../` -> `....`). – Mateus Apr 30 '17 at 21:31
  • @CaseyNeistat It's working normally here: http://rubular.com/r/evhxcMhL3n (p.s. As Rubular doesn't allow you to put a huge regex and save it as a permalink, I couldn't include the `watch?v=...` part, but the full one also works fine). – Mateus Apr 30 '17 at 21:38
  • Take a look at this [Regex101](https://regex101.com/r/SfYvN2/1)'s demo instead. (This one allows me to include the whole regex) – Mateus Apr 30 '17 at 21:42
  • Thanks. I had to add a "^" at the start and then it worked like a charm! – Casey Neistat Apr 30 '17 at 21:59