YouTube Video ID From URL - Swift or Objective-C

16,573

Solution 1

So a YouTube URL looks something like:

http://www.youtube.com/watch?v=oHg5SJYRHA0

The video ID you're interested in is the part at the end (oHg5SJYRHA0).... though it's not necessarily at the end, as YouTube URLs can contain other parameters in the query string.

Your best bet is probably to use a regular expression and Foundation's NSRegularExpression class. I'd presume this approach is used in the other-language tutorials you've found -- note that the content of regular expressions is pretty much the same in any language or toolkit which includes them, so any regex found in those tutorials should work for you. (I'd advise against your approach of breaking on v= and taking exactly 11 characters, as this is prone to various modes of failure to which a regex is more robust.)

To find the video ID you might want a regex like v=([^&]+). The v= gets us to the right part of the query URL (in case we get something like watch?fmt=22&v=oHg5SJYRHA0). The parentheses make a capture group so we can extract only the video ID and not the other matched characters we used to find it, and inside the parentheses we look for a sequence of one or more characters which is not an ampersand -- this makes sure we get everything in the v=whatever field, and no fields after it if you get a URL like watch?v=oHg5SJYRHA0&rel=0.

Whether you use this or another regex, it's likely that you'll be using capture groups. (If not, rangeOfFirstMatchInString:options:range: is just about all you need, as seen in Dima's answer.) You can get at the contents of capture groups (as NSTextCheckingResult objects) using firstMatchInString:options:range: or similar methods:

NSError *error = NULL;
NSRegularExpression *regex = 
[NSRegularExpression regularExpressionWithPattern:@"?.*v=([^&]+)"
                                          options:NSRegularExpressionCaseInsensitive
                                            error:&error];
NSTextCheckingResult *match = [regex firstMatchInString:youtubeURL
                                                options:0
                                                  range:NSMakeRange(0, [youtubeURL length])];
if (match) {
    NSRange videoIDRange = [match rangeAtIndex:1];
    NSString *substringForFirstMatch = [youtubeURL substringWithRange:videoIDRange];
}

Solution 2

Here is RegExp it cover these cases

Objective C

- (NSString *)extractYoutubeIdFromLink:(NSString *)link {
    NSString *regexString = @"((?<=(v|V)/)|(?<=be/)|(?<=(\\?|\\&)v=)|(?<=embed/))([\\w-]++)";
    NSRegularExpression *regExp = [NSRegularExpression regularExpressionWithPattern:regexString
                                                                            options:NSRegularExpressionCaseInsensitive
                                                                              error:nil];

    NSArray *array = [regExp matchesInString:link options:0 range:NSMakeRange(0,link.length)];
    if (array.count > 0) {
        NSTextCheckingResult *result = array.firstObject;
        return [link substringWithRange:result.range];
    }
    return nil;
}

Swift

func extractYoutubeIdFromLink(link: String) -> String? {
    let pattern = "((?<=(v|V)/)|(?<=be/)|(?<=(\\?|\\&)v=)|(?<=embed/))([\\w-]++)"
    guard let regExp = try? NSRegularExpression(pattern: pattern, options: .CaseInsensitive) else {
        return nil
    }
    let nsLink = link as NSString
    let options = NSMatchingOptions(rawValue: 0)
    let range = NSRange(location: 0,length: nsLink.length)
    let matches = regExp.matchesInString(link as String, options:options, range:range)
    if let firstMatch = matches.first {
        return nsLink.substringWithRange(firstMatch.range)
    }
    return nil
}

Swift 3

func extractYoutubeIdFromLink(link: String) -> String? {
    let pattern = "((?<=(v|V)/)|(?<=be/)|(?<=(\\?|\\&)v=)|(?<=embed/))([\\w-]++)"
    guard let regExp = try? NSRegularExpression(pattern: pattern, options: .caseInsensitive) else {
        return nil
    }
    let nsLink = link as NSString
    let options = NSRegularExpression.MatchingOptions(rawValue: 0)
    let range = NSRange(location: 0, length: nsLink.length)
    let matches = regExp.matches(in: link as String, options:options, range:range)
    if let firstMatch = matches.first {
        return nsLink.substring(with: firstMatch.range)
    }
    return nil
}

Solution 3

After spending ages trying to find the correct syntax for the regex, I've come across this which has helped me.

NSString *regexString = @"(?<=v(=|/))([-a-zA-Z0-9_]+)|(?<=youtu.be/)([-a-zA-Z0-9_]+)";

Taken from here. This works for the following URL formats:

 - www.youtube.com/v/VIDEOID  
 - www.youtube.com?v=VIDEOID
 - http://www.youtube.com/watch?v=KFPtWedl7wg&feature=youtu.be
 - http://www.youtube.com/watch?v=MkTD2Y4LXcM 
 - youtu.be/KFPtWedl7wg_U923
 - http://www.youtube.com/watch?feature=player_detailpage&v=biVLGTAMC_U#t=31s

Solution 4

The tutorials you are probably seeing are just instructions on how to use regular expressions, which is also what you want to use in this case.

The Cocoa class you will need to use is NSRegularExpression.

Your actual regex string will depend on the format you are expecting the url to be in since it looks like youtube has several. The general function will look something like:

+ (NSString *)extractYoutubeID:(NSString *)youtubeURL
{
  NSError *error = NULL;  
  NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"your regex string goes here" options:NSRegularExpressionCaseInsensitive error:&error];
  NSRange rangeOfFirstMatch = [regex rangeOfFirstMatchInString:youtubeURL options:0 range:NSMakeRange(0, [youtubeURL length])];
  if(!NSEqualRanges(rangeOfFirstMatch, NSMakeRange(NSNotFound, 0)))
  {
    NSString *substringForFirstMatch = [youtubeURL substringWithRange:rangeOfFirstMatch];

    return substringForFirstMatch;
  }
  return nil;
}

Solution 5

Based on this answer: PHP Regex to get youtube video ID?

I adapted a regex for c/objc/c++ string, the important part here is that the regex doesn't get videos from facebook or other services. iOS regex is based on: ICU

NSString *regexString = @"^(?:http(?:s)?://)?(?:www\\.)?(?:m\\.)?(?:youtu\\.be/|youtube\\.com/(?:(?:watch)?\\?(?:.*&)?v(?:i)?=|(?:embed|v|vi|user)/))([^\?&\"'>]+)";

NSError *error;
NSRegularExpression *regex =
[NSRegularExpression regularExpressionWithPattern:regexString
                                          options:NSRegularExpressionCaseInsensitive
                                            error:&error];
NSTextCheckingResult *match = [regex firstMatchInString:message
                                                options:0
                                                  range:NSMakeRange(0, [message length])];

if (match && match.numberOfRanges == 2) {
    NSRange videoIDRange = [match rangeAtIndex:1];
    NSString *videoID = [message substringWithRange:videoIDRange];
    
    return videoID;
}

Matches:

- youtube.com/v/vidid
- youtube.com/vi/vidid
- youtube.com/?v=vidid
- youtube.com/?vi=vidid
- youtube.com/watch?v=vidid
- youtube.com/watch?vi=vidid
- youtu.be/vidid
- youtube.com/embed/vidid
- http://youtube.com/v/vidid
- http://www.youtube.com/v/vidid
- https://www.youtube.com/v/vidid
- youtube.com/watch?v=vidid&wtv=wtv
- http://www.youtube.com/watch?dev=inprogress&v=vidid&feature=related
- https://m.youtube.com/watch?v=vidid

Does not match:

- www.facebook.com?wtv=youtube.com/v/vidid
- https://www.facebook.com/video.php?v=10155279523025107
Share:
16,573

Related videos on Youtube

The Man
Author by

The Man

Master programmer

Updated on September 09, 2022

Comments

  • The Man
    The Man over 1 year

    I have a Youtube url as an NSString or Swift String, but I need to extract the video id that is displayed in the url. I found many tutorials on how to do this in php or and other web-based programming languages, but none in Objective-C or Swift for Apple platforms...

    I'm looking for a method that asks for an NSString url as the parameter and returns the video id as another NSString...

    • eternalmatt
      eternalmatt almost 12 years
      You could supply an example URL and what you have tried.
  • Dima
    Dima almost 12 years
    updated because I agree, but in general it doesn't matter here.
  • João Nunes
    João Nunes about 11 years
    This worked for me, just to mention that uou ned to access to the range number 0 to get it: NSRange videoIDRange = [match rangeAtIndex:0]; NSString *videoID = [message substringWithRange:videoIDRange];
  • GangstaGraham
    GangstaGraham almost 11 years
    Dis be da cooolest answer evaaa! If it was combined with dat Dima homie's answer
  • Alex
    Alex over 7 years
    @AlmasAdilbek, it's just an example, it is working and you can change it static or convert to String extension, it's up to you
  • Ravi Panchal
    Ravi Panchal about 7 years
    there is still some case where this regex is not working so here is the new regex pattern use this.@"(?<=watch\\?v=|/videos/|embed\\/|youtu.be\\/|\\/v\\/|‌​\\/e\\/|watch\\?v%3D‌​|watch\\?feature=pla‌​yer_embedded&v=|%2Fv‌​ideos%2F|embed%\u200‌​C\u200B2F|youtu.be%2‌​F|%2Fv%2F)[^#\\&\\?\‌​\n]*"
  • Alex
    Alex about 7 years
    @ravi.p can you give me an example when this regex is not working?